1 Functions

source_from_github(repositoy = "DEG_functions",version = "0.2.53")
ℹ SHA-1 hash of file is 8ed4e9017cead897a7d352226a5413f1b5fc0cb7

2 Data

acc1_cancer_cells = readRDS("./Data/acc1_cancer_cells_2500features_integrated_V5.RDS")

all_acc_cancer_cells = readRDS("./Data/acc_cancer_cells_V5_integrated_primary.RDS")
acc_all_cells = readRDS("./Data/acc_tpm_nCount_mito_no146_15k_with_ACC1_.RDS")
acc_cancerCells_noACC1 = subset(all_acc_cancer_cells,subset = patient.ident != "HMSC")

luminal_pathways = c("CHARAFE_BREAST_CANCER_LUMINAL_VS_BASAL_DN","CHARAFE_BREAST_CANCER_LUMINAL_VS_BASAL_UP","CHARAFE_BREAST_CANCER_LUMINAL_VS_MESENCHYMAL_DN","CHARAFE_BREAST_CANCER_LUMINAL_VS_MESENCHYMAL_UP","HUPER_BREAST_BASAL_VS_LUMINAL_DN","LIM_MAMMARY_LUMINAL_PROGENITOR_UP","SMID_BREAST_CANCER_LUMINAL_B_UP" )

# add luminal pathwaysx 
luminal_gs = msigdbr(species = "Homo sapiens") %>% as.data.frame() %>% dplyr::filter(gs_name %in% luminal_pathways)%>% dplyr::distinct(gs_name, gene_symbol) %>% as.data.frame()

3 HMSC vs ACC

3.1 UMAP

DimPlot(all_acc_cancer_cells,group.by = "patient.ident",label = T)

FeaturePlot(object = all_acc_cancer_cells,features = c("MYB"),pt.size = 2)

FeaturePlot(object = all_acc_cancer_cells,features = c("kaye_acc_score"),pt.size = 1)

pdf("./Figures/kaye_acc_score_AllCancerCells.pdf")
FeaturePlot(object = all_acc_cancer_cells,features = c("kaye_acc_score"),pt.size = 1)
dev.off()

3.2 enrichment analysis

enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells),fdr_Cutoff = 0.01,ident.1 = "HMSC",ident.2 = "ACC",show_by = 1)
Welcome to enrichR
Checking connection ... 
Enrichr ... Connection is Live!
FlyEnrichr ... Connection is available!
WormEnrichr ... Connection is available!
YeastEnrichr ... Connection is available!
FishEnrichr ... Connection is available!

3.3 Cell cycle score


hallmark_name = "GO_MITOTIC_CELL_CYCLE"
genesets  =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")


acc_cancerCells_noACC1 = ScaleData(object = acc_cancerCells_noACC1,features = VariableFeatures(acc_cancerCells_noACC1,assay = "integrated"))
geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(acc_cancerCells_noACC1,assay = "integrated")) 
score <- apply(acc_cancerCells_noACC1@assays$integrated@scale.data[geneIds,],2,mean)
acc_cancerCells_noACC1=AddMetaData(acc_cancerCells_noACC1,score,hallmark_name)

acc1_cancer_cells = FindVariableFeatures(object = acc1_cancer_cells,nfeatures = 15000)
acc1_cancer_cells = ScaleData(object = acc1_cancer_cells,features = VariableFeatures(acc1_cancer_cells))
geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(acc1_cancer_cells)) 
score <- apply(acc1_cancer_cells@assays$integrated@scale.data[geneIds,],2,mean)
acc1_cancer_cells=AddMetaData(acc1_cancer_cells,score,hallmark_name)
acc_cc_scores = FetchData(object = acc_cancerCells_noACC1,vars = "GO_MITOTIC_CELL_CYCLE")
hmsc_cc_scores = FetchData(object = acc1_cancer_cells,vars = "GO_MITOTIC_CELL_CYCLE")

distributions_plt = ggplot() +
  geom_density(aes(GO_MITOTIC_CELL_CYCLE, fill = "ACC"), alpha = .2, data = acc_cc_scores) +
  geom_density(aes(GO_MITOTIC_CELL_CYCLE, fill = "HMSC"), alpha = .2, data = hmsc_cc_scores) +
  scale_fill_manual(name = "Dataset", values = c(ACC = "red", HMSC = "green"))+ geom_vline(aes(xintercept=0.3),
            color="blue", linetype="dashed", size=1) +ggtitle("'GO_MITOTIC_CELL_CYCLE'  score distribution")

print_tab(plt = distributions_plt,title = "score distribution",subtitle_num = 3)

score distribution

NA

hmsc_cc_cells = (sum(acc1_cancer_cells@meta.data[[hallmark_name]]> 0.3) /ncol(acc1_cancer_cells)) %>% round(digits = 3)*100
acc_cc_cells = (sum(acc_cancerCells_noACC1@meta.data[[hallmark_name]]> 0.3)/ncol(acc_cancerCells_noACC1)) %>% round(digits = 3)*100
df = data.frame(Dataset = c("HMSC","ACC"), cycling_cells_percentage = c(hmsc_cc_cells,acc_cc_cells))
cycling_cells_plt = ggplot(data=df, aes(x=Dataset, y=cycling_cells_percentage)) +
  geom_text(aes(label=cycling_cells_percentage), vjust=0, color="black", size=3.5)+
  geom_bar(stat="identity")+ylab(" % cycling cells")+
  geom_bar(stat="identity", fill="steelblue")+
  theme_minimal() + ggtitle("Cycling cells count")

print_tab(plt = cycling_cells_plt,title = "# cycling cells",subtitle_num = 3)

# cycling cells

NA

pdf(file = "./Figures/CC_distributions.pdf")
distributions_plt
dev.off()
null device 
          1 
pdf(file = "./Figures/cycling_cells.pdf")
cycling_cells_plt
dev.off()
null device 
          1 
print_tab(plt = 
            FeaturePlot(all_acc_cancer_cells,features = c("MKI67","CDK1","MCM2","CDC20"))
          ,title = "CC genes",subtitle_num = 3)

CC genes

NA

3.4 Cycling cells filtering

#add score to all acc cancer cells
# geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(all_acc_cancer_cells,assay = "integrated")) 
# score <- apply(all_acc_cancer_cells@assays$integrated@scale.data[geneIds,],2,mean)

#add score to all acc cancer cells
cc_all = c(acc_cancerCells_noACC1$GO_MITOTIC_CELL_CYCLE, acc1_cancer_cells$GO_MITOTIC_CELL_CYCLE) %>% as.data.frame()
all_acc_cancer_cells=AddMetaData(all_acc_cancer_cells,cc_all,hallmark_name)

#filter:
all_acc_cancer_cells_ccFiltered=all_acc_cancer_cells[,all_acc_cancer_cells@meta.data[[hallmark_name]]< 0.3]


min_threshold = min(all_acc_cancer_cells$GO_MITOTIC_CELL_CYCLE)
max_threshold = max(all_acc_cancer_cells$GO_MITOTIC_CELL_CYCLE)
library(viridis)

Loading required package: viridisLite

print_tab(plt = FeaturePlot(object = all_acc_cancer_cells,features = hallmark_name) + ggtitle("Before cc filtering") &
            scale_color_gradientn(colours = plasma(n = 10, direction = -1), limits = c(min_threshold, max_threshold))
          ,title = "Before CC filtering",subtitle_num = 3)

Before CC filtering

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

print_tab(plt = 
            FeaturePlot(object = all_acc_cancer_cells_ccFiltered,features = hallmark_name) + ggtitle("After cc filtering") &
            scale_color_gradientn(colours = plasma(n = 10, direction = -1), limits = c(min_threshold, max_threshold))
          ,title = "After CC filtering" ,subtitle_num = 3)

After CC filtering

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

3.5 DEG

all_acc_cancer_cells_ccFiltered = SetIdent(all_acc_cancer_cells_ccFiltered, value ="patient.ident")
acc_deg <-
  FindMarkers(
    all_acc_cancer_cells_ccFiltered,
    ident.1 = "HMSC",
    features = VariableFeatures(all_acc_cancer_cells_ccFiltered),
    densify = T,
    verbose = T,
    slot = "data",
    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1,base = 2)) # change func to calculate logFC in log space data (default to exponent data)
    },
    assay = "RNA"
  )
print_tab(plt = enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells_ccFiltered),fdr_Cutoff = 0.01,ident.1 =
                                      "HMSC",ident.2 = "ACC",show_by = 1)
          ,title = "Enrichment after filtering",subtitle_num = 3)
###   Enrichment after filtering {.unnumbered }  

NA
library(hypeR)
genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG"))
ranked_vec = acc_deg[,"avg_log2FC"]%>% setNames(rownames(acc_deg)) %>% na.omit() # make named vector

hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = F)

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in HMSC")
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in ACC")
plt3 = plt1+plt2
plt3

pdf(file = "./Figures/ACC_vs_HMSC_GSEA.pdf",width = 13,height = 6)
plt3
dev.off()
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,fc_cutoff = 2, ident1 = "HMSC",ident2 = "ACC",top_genes_text = 4)

all_acc_cancer_cells_ccFiltered = SetIdent(all_acc_cancer_cells_ccFiltered, value ="patient.ident")
acc_deg <-
  FindMarkers(
    all_acc_cancer_cells_ccFiltered,
    ident.1 = "HMSC",
    features = VariableFeatures(all_acc_cancer_cells_ccFiltered),
    densify = T,
    verbose = T,
    slot = "data",
    mean.fxn = function(x) {
      return(rowMeans(x) + 1) # change func to calculate logFC in log space data (default to exponent data)
    },
    assay = "RNA"
  )

pdf("./Figures/volcano_plot_ACC_VS_HMSC.pdf")
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,ident1 = "HMSC",ident2 = "ACC",top_genes_text = 3,log2fc_cutoff = 0.5)
dev.off()

pdf("./Figures/Enrichment_analysis_ACC_VS_HMSC.pdf")
enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells_ccFiltered),fdr_Cutoff = 0.01,ident.1 =
                                      "HMSC",ident.2 = "ACC",show_by = 1)
dev.off()
top_hmsc_genes = acc_deg %>% dplyr::filter(avg_log2FC > 0) %>%  slice_min(n = 10,order_by = p_val_adj) %>% rownames()
top_acc_genes = acc_deg %>% dplyr::filter(avg_log2FC < 0) %>%  slice_min(n = 10,order_by = p_val_adj) %>% rownames()
all_top_deg = c(top_hmsc_genes,top_acc_genes)

all_acc_cancer_cells_ccFiltered$cancer_type = all_acc_cancer_cells_ccFiltered$patient.ident %>% gsub(pattern = "ACC.*",replacement = "ACC")
cancer_type = FetchData(object = all_acc_cancer_cells_ccFiltered, vars = "cancer_type")
# col_list = list(circlize::colorRamp2(c(0, 1), c("white", "red"))); names(col_list) = colnames(all_metagenes)[i]
column_ha = HeatmapAnnotation(df = cancer_type)

data = FetchData(object = all_acc_cancer_cells_ccFiltered,vars = all_top_deg,slot = "scale.data") %>% t()

print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, ,name = "Z-score expression",cluster_columns = F,top_annotation = column_ha))

NA
NA

3.6 CNV plot

# create expression matrix of acc + normal cells + HMSC seurat integrated
acc_all_cells_noAcc1 = subset(acc_all_cells, subset = patient.ident != "ACC1")
acc_expr = acc_all_cells_noAcc1@assays$RNA@data %>% as.data.frame()
hmsc_expr  = acc.combined@assays$integrated@data %>% as.data.frame()
acc_expr = acc_expr [ rownames(hmsc_expr),]
all_expr = cbind(acc_expr,hmsc_expr)

# create annotation 
acc_annotation_integrated  = as.data.frame(acc_all_cells@meta.data[,"cell.type",drop = F])
acc_annotation_integrated = acc_annotation_integrated[colnames(all_expr),,drop = F]
acc_annotation_integrated = acc_annotation_integrated %>% rownames_to_column("orig.ident") 

# #write expression and annotation
# write.table(acc_annotation_integrated, "./Data/inferCNV/acc_annotation_integrated.txt", append = FALSE, 
#             sep = "\t", dec = ".",row.names = FALSE, col.names = F)
# 
# 
# write.table(all_expr, "./Data/inferCNV/all.4icnv_integrated.txt", append = FALSE, 
#             sep = "\t", dec = ".",row.names = T, col.names = T)
trace(infercnv::run,edit = T) # to skip normalization, change to skip_past = 4 (https://github.com/broadinstitute/infercnv/issues/346)
Tracing function "run" in package "infercnv"
[1] "run"

infercnv_obj = CreateInfercnvObject(raw_counts_matrix="./Data/inferCNV/all.4icnv_integrated.txt", 
                                    annotations_file="./Data/inferCNV/acc_annotation_integrated.txt",
                                    delim="\t",gene_order_file="./Data/inferCNV/gencode_v19_gene_pos.txt"
                                    ,ref_group_names=c("CAF", "Endothelial", "WBC")) #groups of normal cells

infercnv_obj_default = infercnv::run(infercnv_obj, cutoff=1, out_dir='./Data/inferCNV/infercnv_intergrated_output',
                                     cluster_by_groups=T, plot_steps=FALSE,
                                     denoise=TRUE, HMM=FALSE, no_prelim_plot=TRUE,
                                     png_res=300)
untrace(infercnv::run)
trace(infercnv:::get_group_color_palette ,edit = T) # change "Set3" to "Set1" for more distinguishable colors
plot_cnv(infercnv_obj_default, output_format = "png",  write_expr_matrix = FALSE,out_dir = "./Data/inferCNV/infercnv_intergrated_output",png_res    =800,obs_title = "Malignant cells",ref_title = "Normal cells",contig_cex = 2, title = "Copy number variation")
untrace(infercnv:::get_group_color_palette)
print_tab(plt = knitr::include_graphics("./Data/inferCNV/infercnv_intergrated_output/infercnv.png")
          ,title = "CNV plot",subtitle_num = 3)

CNV plot

NA

library(limma)
smoothed=apply(infercnv_obj_default@expr.data,2,tricubeMovingAverage, span=0.01)
cnsig=sqrt(apply((smoothed-1)^2,2,mean))

acc_all_cells <- AddMetaData(object = acc_all_cells, metadata = cnsig, col.name = "copynumber")
acc_all_cells = SetIdent(object = acc_all_cells,value = "cell.type")

print_tab(plt = FeaturePlot(acc_all_cells, "copynumber",pt.size = 1,label = T,repel = T)+
            scale_colour_gradientn(colours=c("white","lightblue","orange","red","darkred"))
          ,title = "CNV UMAP",subtitle_num = 3)

CNV UMAP

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

4 HMSC analysis

4.1 UMAP

acc1_cancer_cells = FindClusters(object = acc1_cancer_cells,verbose = F,resolution = 0.5)
DimPlot(object = acc1_cancer_cells,pt.size = 2)

4.2 Scores

FeaturePlot(object = acc1_cancer_cells,features = c("MYB","JAG1"),pt.size = 2)+
DimPlot(object = acc1_cancer_cells,group.by  = c("hpv33_positive"),pt.size = 2)

4.3 DEG

SetIdent(object = acc1_cancer_cells,value = "seurat_clusters")

An object of class Seurat 80474 features across 134 samples within 2 assays Active assay: integrated (40237 features, 15000 variable features) 1 other assay present: RNA 2 dimensional reductions calculated: pca, umap

deg = FindAllMarkers(object = acc1_cancer_cells,features = VariableFeatures(acc1_cancer_cells),densify = T,verbose = F)
for (cluster in unique(deg$cluster)) {
  print_tab(plt = deg[deg$cluster == cluster,],title = "DEG" ,subtitle_num = toc_tabs_level)
}

DEG

DEG

NA

for (cluster in unique(deg$cluster)) {
  deg_of_cluster = deg[deg$cluster == cluster,] 
  #  print(deg_of_cluster %in% original_myo_genes %>% which())
  # print(deg_of_cluster %in% original_lum_genes %>% which())
  print_tab(plt = 
              enrichment_analysis(deg_of_cluster,background =VariableFeatures(acc1_cancer_cells),fdr_Cutoff = 0.01,ident.1 =
                                   paste("Cluster",cluster),ident.2 =  paste("Cluster",cluster),show_by = 1)
            ,title = cluster,subtitle_num = toc_tabs_level)
}

4.4 NMF

from cnmf import cNMF
AttributeError: module 'matplotlib' has no attribute 'get_data_path'
knitr::include_graphics("./Data/cNMF/HMSC_cNMF_harmony_2Kvargenes/HMSC_cNMF_harmony_2Kvargenes.k_selection.png")
selected_k = 3
density_threshold = 0.1
cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold,show_clustering=True)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
all_metagenes= py$usage_norm

4.5 Harmony results

# Make metagene names
for (i in 1:ncol(all_metagenes)) {
  colnames(all_metagenes)[i] = "metagene." %>% paste0(i)
}

#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
  metage_metadata = all_metagenes %>% select(i)
  acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}

Note: Using an external vector in selections is ambiguous. ℹ Use all_of(i) instead of i to silence this message. ℹ See https://tidyselect.r-lib.org/reference/faq-external-vector.html. This message is displayed once per session.

print_tab(plt = 
            FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),combine = T),
          title = "metagenes expression",subtitle_num = toc_tabs_level)

metagenes expression

#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
  metage_metadata = all_metagenes %>% select(i)
  lung_corr_nonneg = AddMetaData(object = lung_corr_nonneg,metadata = metage_metadata)
}
print_tab(plt = 
            FeaturePlot(object = lung_corr_nonneg,features = colnames(all_metagenes),combine = T),
          title = "metagenes expression",subtitle_num = toc_tabs_level)

metagenes expression

NA

4.6 Enrichment analysis by top 200 genes of each program


# canonical_pathways = msigdbr(species = "Homo sapiens", category = "C2") %>% dplyr::filter(gs_subcat != "CGP") %>%  dplyr::distinct(gs_name, gene_symbol) 

plt_list = list()
for (i in 1:ncol(gep_scores)) {
  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),200) #take top top_genes_num
  res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title = 
                    i,silent = T,return_all = T,custom_pathways = canonical_pathways)
   
  plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

for (i in 1:ncol(gep_scores)) {
  ranked_vec = gep_scores %>% pull(i) %>%  setNames(rownames(gep_scores))
  hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = T)

  plt = hyp_dots(hyp_obj,merge = F)+ aes(size=abs(nes))
  print(plt)
}

for (i in 1:ncol(gep_scores)) {
  gep_scores = gep_scores  %>%  arrange(desc(gep_scores[i])) 
  ranked_vec = gep_scores %>% pull(i) %>%  setNames(rownames(gep_scores))
  hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = T)

  plt = hyp_dots(hyp_obj,merge = F)
  print(plt)
}

library(ComplexHeatmap)
acc1_cancer_cells = SetIdent(object = acc1_cancer_cells,value = "seurat_clusters")
for (i in 1:ncol(gep_scores)) {
  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),50) #take top top_genes_num
  data = FetchData(object = acc1_cancer_cells,vars = top)%>% scale() %>% t() 
  metagene_data = FetchData(object = acc1_cancer_cells,vars = colnames(all_metagenes)[i])
  col_list = list(circlize::colorRamp2(c(0, 1), c("white", "red"))); names(col_list) = colnames(all_metagenes)[i]
  column_ha = HeatmapAnnotation(df = metagene_data,col = col_list)
  pdf(paste0("./Figures/NMF_top_genes_program",i,".pdf"))
  print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, top_annotation = column_ha,name = "Z-score expression"))
  dev.off()
}

4.7 Lum Myo score

original_myo_genes = c( "TP63", "TP73", "CAV1", "CDH3", "KRT5", "KRT14", "ACTA2", "TAGLN", "MYLK", "DKK3")
original_lum_genes = c("KIT", "EHF", "ELF5", "KRT7", "CLDN3", "CLDN4", "CD24", "LGALS3", "LCN2", "SLPI" )
FeaturePlot(acc1_cancer_cells,features = original_myo_genes)
FeaturePlot(acc1_cancer_cells,features = original_lum_genes)
all_acc_cancer_cells = SetIdent(all_acc_cancer_cells,value = "patient.ident")
calculate_score(dataset = all_acc_cancer_cells,myo_genes = original_myo_genes,lum_genes = original_lum_genes)
myo_expr = FetchData(object = acc1_cancer_cells,vars = c(original_myo_genes))
myo_cor = cor(myo_expr)
pheatmap(myo_cor)

myo_expr = FetchData(object = acc1_cancer_cells,vars = c(original_lum_genes))
myo_cor = cor(myo_expr)
pheatmap(myo_cor)

myo_expr = FetchData(object = acc_cancerCells_noACC1,vars = c(original_myo_genes))
myo_cor = cor(myo_expr)
pheatmap(myo_cor)

myo_expr = FetchData(object = acc_cancerCells_noACC1,vars = c(top_lum,lum))
myo_cor = cor(myo_expr)
pheatmap(myo_cor)

4.8 Original score of ACC1

lum = c("LCN2","CLDN3","ELF5","MMP7", "GABRP","CALML5","EFNA5")
myo = myo_enriched_genes
trace(calculate_score, edit = T)
calculate_score(dataset = acc1_cancer_cells,myo_genes = original_myo_genes,lum_genes = original_lum_genes,lum_threshold = 0,myo_threshold = 0)
cd_features <- list(original_myo_genes)
acc1_cancer_cells <- AddModuleScore(
  object = acc1_cancer_cells,
  features = cd_features,
  ctrl = 5,
  name = 'myo_Features'
)

FeaturePlot(object = acc1_cancer_cells,features = "myo_Features1")
cd_features <- list(c("KRT7",   "LGALS3" ,"LCN2"  , "SLPI"))
acc1_cancer_cells <- AddModuleScore(
  object = acc1_cancer_cells,
  features = cd_features,
  ctrl = 5,
  name = 'lum_Features'
)

FeaturePlot(object = acc1_cancer_cells,features = "lum_Features1")
cor(acc1_cancer_cells$lum_Feoriginal_myo_genesatures1,acc1_cancer_cells$myo_Features1)

4.8.1 Myo genes

myo_protein_markers = c("CNN1", "TP63","ACTA2")
top_myo  = top_correlated(dataset = acc1_cancer_cells, genes = myo_protein_markers,threshold = 0.35)
print("Number of genes = " %>% paste(length(top_myo)))
message("Names of genes:")
top_myo %>% head(30)
message("Genes that also apeared in the original score:")
base::intersect(top_myo,original_myo_genes) 
myo_enrich_res = genes_vec_enrichment(genes = top_myo,background = rownames(acc1_cancer_cells),homer = T,title = "myo top enrichment",custom_pathways = luminal_gs)
myo_enrich_res

4.8.2 Lum genes

lum_protein_markers = c("KIT")
top_lum  = top_correlated(dataset = acc1_cancer_cells, genes = lum_protein_markers,threshold = 0.30,n_vargenes = 5000)
print("Number of genes = " %>% paste(length(top_lum)))
message("Names of genes:")
top_lum %>% head(30)
message("Genes that also apeared in the original score:")
base::intersect(top_lum,original_lum_genes) 
lum_enrich_res = genes_vec_enrichment(genes = top_lum,background = rownames(acc1_cancer_cells),homer = T,title = "lum top enrichment",custom_pathways = luminal_gs)
lum_enrich_res
rownames(myo_enrich_res) = myo_enrich_res$pathway_name
myo_enriched_genes = myo_enrich_res[1,"geneID"] %>% strsplit(split = "/") %>% .[[1]] %>% c(.,myo_protein_markers) #add original markers
myoscore=FetchData(object =acc1_cancer_cells,vars =  myo_enriched_genes,slot = "data") %>% rowMeans()
acc1_cancer_cells=AddMetaData(acc1_cancer_cells,myoscore,"myo_score")


myoscore=FetchData(object =acc1_cancer_cells,vars =  top_myo,slot = "data") %>% rowMeans()
acc1_cancer_cells=AddMetaData(acc1_cancer_cells,myoscore,"myo_score")

4.9 HPV

4.9.1 HPV UMAP

HPV33_P3 = fread("./Data/HPV33_P3.txt",col.names = c("plate","reads")) %>% as.data.frame()
HPV33_P3.df = HPV33_P3 %>% mutate(
  plate = gsub(x =HPV33_P3$plate, replacement = "",pattern = "_.*$") 
  %>% gsub(pattern = "-P",replacement = ".P") 
  %>% gsub(pattern = "-",replacement = "_",)
  )
HPV33_P3.df = HPV33_P3.df %>% dplyr::filter(HPV33_P3.df$plate %in% colnames(acc1_cancer_cells))
rownames(HPV33_P3.df)  <- HPV33_P3.df$plate
HPV33_P3.df$plate = NULL


HPV33_P2 = fread("./Data/HPV33_P2.txt",col.names = c("plate","reads")) %>% as.data.frame()
HPV33_P2.df = HPV33_P2 %>% mutate(
  plate = gsub(x =HPV33_P2$plate, replacement = "",pattern = "_.*$") 
  %>% gsub(pattern = "plate2-",replacement = "plate2_",)
  %>% gsub(pattern = "-",replacement = "\\.",)
  )
HPV33_P2.df = HPV33_P2.df %>% dplyr::filter(HPV33_P2.df$plate %in% colnames(acc1_cancer_cells))
rownames(HPV33_P2.df)  <- HPV33_P2.df$plate
HPV33_P2.df$plate = NULL

HPV33 = rbind(HPV33_P3.df,HPV33_P2.df)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = HPV33,col.name = "HPV33.reads")
FeaturePlot(acc1_cancer_cells,features = "HPV33.reads",max.cutoff = 10)

data = FetchData(object = acc1_cancer_cells,vars = "HPV33.reads")

data = data %>% mutate("0 reads" = if_else(condition = HPV33.reads == 0,true = 1,false = 0))
data = data %>% mutate("1 reads" = if_else(condition = HPV33.reads == 1,true = 1,false = 0))
data = data %>% mutate("2 reads" = if_else(condition = HPV33.reads == 2,true = 1,false = 0))
data = data %>% mutate("3-23 reads" = if_else(condition = HPV33.reads >=3 &HPV33.reads  <24,true = 1,false = 0))
data = data %>% mutate("24+ reads" = if_else(condition = HPV33.reads >=24,true = 1,false = 0))
data = colSums(data[,2:ncol(data)]) %>% as.data.frame()
names(data)[1] = "count"
data = rownames_to_column(data,var = "bin")
data
ggplot(data=data, aes(x=factor(bin,levels = c("0 reads","1 reads","2 reads","3-23 reads","24+ reads")), y=count)) +
  geom_bar(stat="identity", fill="steelblue") + xlab("HPV Reads")+ theme_minimal()+
  geom_text(aes(label=count), vjust=-0.5, color="black", size=3.5)
hpv33_positive = HPV33 %>% dplyr::mutate(hpv33_positive = case_when(reads >= 10 ~ "positive",
                                                                    reads < 10 ~ "negative")
)



hpv33_positive$reads = NULL
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = hpv33_positive)
DimPlot(object = acc1_cancer_cells,group.by  = c("hpv33_positive"),pt.size = 2)

library(biomaRt)
ensembl = useEnsembl(biomart="ensembl", dataset="hsapiens_gene_ensembl")
all_up_genes
# library("biomaRt")
# mart <- useMart(biomart="ensembl", dataset="hsapiens_gene_ensembl")
# all_coding_genes <- getBM(attributes = c( "hgnc_symbol"), filters = c("biotype"), values = list(biotype="protein_coding"), mart = mart)

acc1_cancer_cells = FindVariableFeatures(acc1_cancer_cells,nfeatures = 15000)
acc1_cancer_cells = SetIdent(acc1_cancer_cells, value ="hpv33_positive")
features = VariableFeatures(acc1_cancer_cells) 
acc_deg <-
  FindMarkers(
    acc1_cancer_cells,
    ident.1 = "positive",
    ident.2 = "negative",
    features = features,
    densify = T,
    assay = "RNA",
    test.use = "LR",
    latent.vars = "plate",
    logfc.threshold = 0.25,
    min.pct = 0.15,
    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1, base = 2)) # change func to calculate logFC in log space data (default to exponent data)
    }
  )
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr" )
ranked_vec = acc_deg[,"avg_log2FC"]%>% setNames(rownames(acc_deg)) %>% na.omit() # make named vector

hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = F)
hyp_dots(hyp_obj,merge = F)
acc_deg
acc_deg[c("MYB","JAG1"),]
NA
volcano_plot(de_genes = acc_deg,fc_cutoff = 1.3, fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)

# library("biomaRt")
# mart <- useMart(biomart="ensembl", dataset="hsapiens_gene_ensembl")
# all_coding_genes <- getBM(attributes = c( "hgnc_symbol"), filters = c("biotype"), values = list(biotype="protein_coding"), mart = mart)

acc1_cancer_cells = FindVariableFeatures(acc1_cancer_cells,nfeatures = 15000)
acc1_cancer_cells = SetIdent(acc1_cancer_cells, value ="hpv33_positive")
features = VariableFeatures(acc1_cancer_cells) 
acc_deg <-
  FindMarkers(
    acc1_cancer_cells,
    ident.1 = "positive",
    ident.2 = "negative",
    features = features,
    densify = T,
    assay = "RNA",
    test.use = "LR",
    latent.vars = "plate",
    logfc.threshold = 0.5,
    min.pct = 0.15,
    mean.fxn = function(x) {
      return(rowMeans(x) + 1) # change func to calculate logFC in log space data (default to exponent data)
    }
  )
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr" )
acc_deg
acc_deg[c("MYB","JAG1"),]
NA
volcano_plot(de_genes = acc_deg,fc_cutoff = 1.3, fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)+xlab("avg diff")

4.9.2 HPV vs genes

notch_genes = c("JAG1","JAG2","NOTCH3","NOTCH2","NOTCH1","DLL1","MYB","HES4","HEY1","HEY2","NRARP","myo_score")
for (gene  in notch_genes) {
  myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive",gene)) 
  myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)

  p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = gene,
            palette = "jco",
            add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV33 positive","HPV33 negative")))+ stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(gene)
  print_tab(p,title = gene)
}
myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive",c("JAG1","JAG2"))) 
myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)
df = melt(myb_vs_hpv)

ggboxplot(df, x = "variable", y = "value",color = "hpv33_positive",
            palette = "jco",
            add = "jitter") + stat_compare_means(method = "t.test", ref.group = ".all.") & stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text")
notch_targets = c("NOTCH3","HES4","HEY1","HEY2","NRARP") 
notch_ligand = c("JAG1","JAG2","DLL1")
notch_genes = list(notch_targets = notch_targets,notch_ligand = notch_ligand)
for (i  in 1:length(notch_genes)) {
  genes = notch_genes[[i]]
  name = names( notch_genes)[i]
  myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c(genes)) %>% rowMeans()
  myb_vs_hpv = myb_vs_hpv %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive")))
  colnames(myb_vs_hpv)[1] = "gene_set"
  myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)

  p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = "gene_set",
            palette = "jco",
            add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV33 positive","HPV33 negative")))+ stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(name)
 print(p)
}
  cor_data = FetchData(object = acc1_cancer_cells,vars = c("MYB","myo_score"))
ggplot(cor_data, aes(x=MYB, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()


  cor_data = FetchData(object = acc1_cancer_cells,vars = c("JAG1","myo_score"))
ggplot(cor_data, aes(x=JAG1, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()

  cor_data = FetchData(object = acc1_cancer_cells,vars = c("JAG2","myo_score"))
ggplot(cor_data, aes(x=JAG2, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()

  cor_data = FetchData(object = acc1_cancer_cells,vars = c("DLL1","myo_score"))
ggplot(cor_data, aes(x=DLL1, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()


  cor_data = FetchData(object = acc1_cancer_cells,vars = notch_targets) %>% rowMeans()
  cor_data = cor_data %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("myo_score")))
  colnames(cor_data)[1] = "notch_targets"

  ggplot(cor_data, aes(x=notch_targets, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()
  
  
    cor_data = FetchData(object = acc1_cancer_cells,vars = notch_ligand) %>% rowMeans()
  cor_data = cor_data %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("myo_score")))
  colnames(cor_data)[1] = "notch_ligand"

  ggplot(cor_data, aes(x=notch_ligand, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()
  
notch_score = FetchData(object = all_acc_cancer_cells,vars = notch_targets) %>% rowMeans()
all_acc_cancer_cells  = AddMetaData(object = all_acc_cancer_cells,metadata = notch_score,col.name = "notch_score")
FeaturePlot(object = all_acc_cancer_cells,features = "notch_score" )
myo_markers = c("TP63", "TP73", "KRT14", "CDH3")
score = FetchData(object = acc1_cancer_cells,vars = myo_markers) %>% rowMeans()
acc1_cancer_cells  = AddMetaData(object = acc1_cancer_cells,metadata = score,col.name = "myo_markers_score")
FeaturePlot(object = acc1_cancer_cells,features = "myo_markers_score",pt.size = 2 )


markers = c("CLDN3", "ANXA8", "EHF", "KIT")
score = FetchData(object = acc1_cancer_cells,vars = markers) %>% rowMeans()
acc1_cancer_cells  = AddMetaData(object = acc1_cancer_cells,metadata = score,col.name = "lum_markers_score")
FeaturePlot(object = acc1_cancer_cells,features = "lum_markers_score" ,pt.size = 2 )
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMgotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiREVHX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjIuNTMiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkhNU0NfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMS4xNCIsc2NyaXB0X25hbWUgPSAiZnVuY3Rpb25zLlIiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gImNOTUZfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMy45IixzY3JpcHRfbmFtZSA9ICJjbm1mX2Z1bmN0aW9uX0hhcm1vbnkuUiIpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAic2NfZ2VuZXJhbF9mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4xLjM0IixzY3JpcHRfbmFtZSA9ICJmdW5jdGlvbnMuUiIpCgp0b2NfdGFic19sZXZlbCA9MwpgYGAKCiMgRGF0YQoKYGBge3J9CmFjYzFfY2FuY2VyX2NlbGxzID0gcmVhZFJEUygiLi9EYXRhL2FjYzFfY2FuY2VyX2NlbGxzXzI1MDBmZWF0dXJlc19pbnRlZ3JhdGVkX1Y1LlJEUyIpCgphbGxfYWNjX2NhbmNlcl9jZWxscyA9IHJlYWRSRFMoIi4vRGF0YS9hY2NfY2FuY2VyX2NlbGxzX1Y1X2ludGVncmF0ZWRfcHJpbWFyeS5SRFMiKQphY2NfYWxsX2NlbGxzID0gcmVhZFJEUygiLi9EYXRhL2FjY190cG1fbkNvdW50X21pdG9fbm8xNDZfMTVrX3dpdGhfQUNDMV8uUkRTIikKYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IHN1YnNldChhbGxfYWNjX2NhbmNlcl9jZWxscyxzdWJzZXQgPSBwYXRpZW50LmlkZW50ICE9ICJITVNDIikKCmx1bWluYWxfcGF0aHdheXMgPSBjKCJDSEFSQUZFX0JSRUFTVF9DQU5DRVJfTFVNSU5BTF9WU19CQVNBTF9ETiIsIkNIQVJBRkVfQlJFQVNUX0NBTkNFUl9MVU1JTkFMX1ZTX0JBU0FMX1VQIiwiQ0hBUkFGRV9CUkVBU1RfQ0FOQ0VSX0xVTUlOQUxfVlNfTUVTRU5DSFlNQUxfRE4iLCJDSEFSQUZFX0JSRUFTVF9DQU5DRVJfTFVNSU5BTF9WU19NRVNFTkNIWU1BTF9VUCIsIkhVUEVSX0JSRUFTVF9CQVNBTF9WU19MVU1JTkFMX0ROIiwiTElNX01BTU1BUllfTFVNSU5BTF9QUk9HRU5JVE9SX1VQIiwiU01JRF9CUkVBU1RfQ0FOQ0VSX0xVTUlOQUxfQl9VUCIgKQoKIyBhZGQgbHVtaW5hbCBwYXRod2F5c3ggCmx1bWluYWxfZ3MgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIikgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OmZpbHRlcihnc19uYW1lICVpbiUgbHVtaW5hbF9wYXRod2F5cyklPiUgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKSAlPiUgYXMuZGF0YS5mcmFtZSgpCmBgYAoKCgoKIyBITVNDIHZzIEFDQwoKIyMgVU1BUAoKYGBge3J9CkRpbVBsb3QoYWxsX2FjY19jYW5jZXJfY2VsbHMsZ3JvdXAuYnkgPSAicGF0aWVudC5pZGVudCIsbGFiZWwgPSBUKQpgYGAKCmBgYHtyfQpGZWF0dXJlUGxvdChvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGMoIk1ZQiIpLHB0LnNpemUgPSAyKQpgYGAKYGBge3J9CkZlYXR1cmVQbG90KG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gYygia2F5ZV9hY2Nfc2NvcmUiKSxwdC5zaXplID0gMSkKCmBgYApgYGB7cn0KcGRmKCIuL0ZpZ3VyZXMva2F5ZV9hY2Nfc2NvcmVfQWxsQ2FuY2VyQ2VsbHMucGRmIikKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjKCJrYXllX2FjY19zY29yZSIpLHB0LnNpemUgPSAxKQpkZXYub2ZmKCkKYGBgCgojIyBlbnJpY2htZW50IGFuYWx5c2lzIAoKYGBge3IgZmlnLndpZHRoPTgsIGVjaG89VFJVRSxyZXN1bHRzPSdoaWRlJyxmaWcua2VlcD0nYWxsJ30KYWxsX2FjY19jYW5jZXJfY2VsbHMgPSBTZXRJZGVudChhbGxfYWNjX2NhbmNlcl9jZWxscywgdmFsdWUgPSJwYXRpZW50LmlkZW50IikKYWNjX2RlZyA8LQogIEZpbmRNYXJrZXJzKAogICAgYWxsX2FjY19jYW5jZXJfY2VsbHMsCiAgICBpZGVudC4xID0gIkhNU0MiLAogICAgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFsbF9hY2NfY2FuY2VyX2NlbGxzKSwKICAgIGRlbnNpZnkgPSBULAogICAgYXNzYXkgPSAiUk5BIiwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4obG9nKHJvd01lYW5zKHgpICsgMSwgYmFzZSA9IDIpKSAjIGNoYW5nZSBmdW5jIHRvIGNhbGN1bGF0ZSBsb2dGQyBpbiBsb2cgc3BhY2UgZGF0YSAoZGVmYXVsdCB0byBleHBvbmVudCBkYXRhKQogICAgfQogICkKCmBgYAoKYGBge3J9CmVucmljaG1lbnRfYW5hbHlzaXMoYWNjX2RlZyxiYWNrZ3JvdW5kID0gVmFyaWFibGVGZWF0dXJlcyhhbGxfYWNjX2NhbmNlcl9jZWxscyksZmRyX0N1dG9mZiA9IDAuMDEsaWRlbnQuMSA9ICJITVNDIixpZGVudC4yID0gIkFDQyIsc2hvd19ieSA9IDEpCmBgYAoKIyMgQ2VsbCBjeWNsZSBzY29yZSAgey50YWJzZXR9CmBgYHtyfQoKaGFsbG1hcmtfbmFtZSA9ICJHT19NSVRPVElDX0NFTExfQ1lDTEUiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQoKCmFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBTY2FsZURhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWNjX2NhbmNlckNlbGxzX25vQUNDMSxhc3NheSA9ICJpbnRlZ3JhdGVkIikpCmdlbmVJZHM9IGdlbmVzZXRzW1toYWxsbWFya19uYW1lXV1AZ2VuZUlkcyAlPiUgaW50ZXJzZWN0KFZhcmlhYmxlRmVhdHVyZXMoYWNjX2NhbmNlckNlbGxzX25vQUNDMSxhc3NheSA9ICJpbnRlZ3JhdGVkIikpIApzY29yZSA8LSBhcHBseShhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxQGFzc2F5cyRpbnRlZ3JhdGVkQHNjYWxlLmRhdGFbZ2VuZUlkcyxdLDIsbWVhbikKYWNjX2NhbmNlckNlbGxzX25vQUNDMT1BZGRNZXRhRGF0YShhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHNjb3JlLGhhbGxtYXJrX25hbWUpCgphY2MxX2NhbmNlcl9jZWxscyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG5mZWF0dXJlcyA9IDE1MDAwKQphY2MxX2NhbmNlcl9jZWxscyA9IFNjYWxlRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWNjMV9jYW5jZXJfY2VsbHMpKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMgJT4lIGludGVyc2VjdChWYXJpYWJsZUZlYXR1cmVzKGFjYzFfY2FuY2VyX2NlbGxzKSkgCnNjb3JlIDwtIGFwcGx5KGFjYzFfY2FuY2VyX2NlbGxzQGFzc2F5cyRpbnRlZ3JhdGVkQHNjYWxlLmRhdGFbZ2VuZUlkcyxdLDIsbWVhbikKYWNjMV9jYW5jZXJfY2VsbHM9QWRkTWV0YURhdGEoYWNjMV9jYW5jZXJfY2VsbHMsc2NvcmUsaGFsbG1hcmtfbmFtZSkKCgoKYGBgCgoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KYWNjX2NjX3Njb3JlcyA9IEZldGNoRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHZhcnMgPSAiR09fTUlUT1RJQ19DRUxMX0NZQ0xFIikKaG1zY19jY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9ICJHT19NSVRPVElDX0NFTExfQ1lDTEUiKQoKZGlzdHJpYnV0aW9uc19wbHQgPSBnZ3Bsb3QoKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhHT19NSVRPVElDX0NFTExfQ1lDTEUsIGZpbGwgPSAiQUNDIiksIGFscGhhID0gLjIsIGRhdGEgPSBhY2NfY2Nfc2NvcmVzKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhHT19NSVRPVElDX0NFTExfQ1lDTEUsIGZpbGwgPSAiSE1TQyIpLCBhbHBoYSA9IC4yLCBkYXRhID0gaG1zY19jY19zY29yZXMpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkRhdGFzZXQiLCB2YWx1ZXMgPSBjKEFDQyA9ICJyZWQiLCBITVNDID0gImdyZWVuIikpKyBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PTAuMyksCiAgICAgICAgICAgIGNvbG9yPSJibHVlIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgK2dndGl0bGUoIidHT19NSVRPVElDX0NFTExfQ1lDTEUnICBzY29yZSBkaXN0cmlidXRpb24iKQoKcHJpbnRfdGFiKHBsdCA9IGRpc3RyaWJ1dGlvbnNfcGx0LHRpdGxlID0gInNjb3JlIGRpc3RyaWJ1dGlvbiIsc3VidGl0bGVfbnVtID0gMykKCmBgYApgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpobXNjX2NjX2NlbGxzID0gKHN1bShhY2MxX2NhbmNlcl9jZWxsc0BtZXRhLmRhdGFbW2hhbGxtYXJrX25hbWVdXT4gMC4zKSAvbmNvbChhY2MxX2NhbmNlcl9jZWxscykpICU+JSByb3VuZChkaWdpdHMgPSAzKSoxMDAKYWNjX2NjX2NlbGxzID0gKHN1bShhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxQG1ldGEuZGF0YVtbaGFsbG1hcmtfbmFtZV1dPiAwLjMpL25jb2woYWNjX2NhbmNlckNlbGxzX25vQUNDMSkpICU+JSByb3VuZChkaWdpdHMgPSAzKSoxMDAKZGYgPSBkYXRhLmZyYW1lKERhdGFzZXQgPSBjKCJITVNDIiwiQUNDIiksIGN5Y2xpbmdfY2VsbHNfcGVyY2VudGFnZSA9IGMoaG1zY19jY19jZWxscyxhY2NfY2NfY2VsbHMpKQpjeWNsaW5nX2NlbGxzX3BsdCA9IGdncGxvdChkYXRhPWRmLCBhZXMoeD1EYXRhc2V0LCB5PWN5Y2xpbmdfY2VsbHNfcGVyY2VudGFnZSkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWN5Y2xpbmdfY2VsbHNfcGVyY2VudGFnZSksIHZqdXN0PTAsIGNvbG9yPSJibGFjayIsIHNpemU9My41KSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK3lsYWIoIiAlIGN5Y2xpbmcgY2VsbHMiKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9InN0ZWVsYmx1ZSIpKwogIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkN5Y2xpbmcgY2VsbHMgY291bnQiKQoKcHJpbnRfdGFiKHBsdCA9IGN5Y2xpbmdfY2VsbHNfcGx0LHRpdGxlID0gIiMgY3ljbGluZyBjZWxscyIsc3VidGl0bGVfbnVtID0gMykKYGBgCmBgYHtyfQpwZGYoZmlsZSA9ICIuL0ZpZ3VyZXMvQ0NfZGlzdHJpYnV0aW9ucy5wZGYiKQpkaXN0cmlidXRpb25zX3BsdApkZXYub2ZmKCkKCnBkZihmaWxlID0gIi4vRmlndXJlcy9jeWNsaW5nX2NlbGxzLnBkZiIpCmN5Y2xpbmdfY2VsbHNfcGx0CmRldi5vZmYoKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRmVhdHVyZVBsb3QoYWxsX2FjY19jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjKCJNS0k2NyIsIkNESzEiLCJNQ00yIiwiQ0RDMjAiKSkKICAgICAgICAgICx0aXRsZSA9ICJDQyBnZW5lcyIsc3VidGl0bGVfbnVtID0gMykKYGBgCgojIyBDeWNsaW5nIGNlbGxzIGZpbHRlcmluZyB7LnRhYnNldH0KYGBge3Igd2FybmluZz1GQUxTRX0KI2FkZCBzY29yZSB0byBhbGwgYWNjIGNhbmNlciBjZWxscwojIGdlbmVJZHM9IGdlbmVzZXRzW1toYWxsbWFya19uYW1lXV1AZ2VuZUlkcyAlPiUgaW50ZXJzZWN0KFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHMsYXNzYXkgPSAiaW50ZWdyYXRlZCIpKSAKIyBzY29yZSA8LSBhcHBseShhbGxfYWNjX2NhbmNlcl9jZWxsc0Bhc3NheXMkaW50ZWdyYXRlZEBzY2FsZS5kYXRhW2dlbmVJZHMsXSwyLG1lYW4pCgojYWRkIHNjb3JlIHRvIGFsbCBhY2MgY2FuY2VyIGNlbGxzCmNjX2FsbCA9IGMoYWNjX2NhbmNlckNlbGxzX25vQUNDMSRHT19NSVRPVElDX0NFTExfQ1lDTEUsIGFjYzFfY2FuY2VyX2NlbGxzJEdPX01JVE9USUNfQ0VMTF9DWUNMRSkgJT4lIGFzLmRhdGEuZnJhbWUoKQphbGxfYWNjX2NhbmNlcl9jZWxscz1BZGRNZXRhRGF0YShhbGxfYWNjX2NhbmNlcl9jZWxscyxjY19hbGwsaGFsbG1hcmtfbmFtZSkKCiNmaWx0ZXI6CmFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQ9YWxsX2FjY19jYW5jZXJfY2VsbHNbLGFsbF9hY2NfY2FuY2VyX2NlbGxzQG1ldGEuZGF0YVtbaGFsbG1hcmtfbmFtZV1dPCAwLjNdCgoKbWluX3RocmVzaG9sZCA9IG1pbihhbGxfYWNjX2NhbmNlcl9jZWxscyRHT19NSVRPVElDX0NFTExfQ1lDTEUpCm1heF90aHJlc2hvbGQgPSBtYXgoYWxsX2FjY19jYW5jZXJfY2VsbHMkR09fTUlUT1RJQ19DRUxMX0NZQ0xFKQpgYGAKCgpgYGB7ciwgcmVzdWx0cz0nYXNpcyd9CmxpYnJhcnkodmlyaWRpcykKCnByaW50X3RhYihwbHQgPSBGZWF0dXJlUGxvdChvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGhhbGxtYXJrX25hbWUpICsgZ2d0aXRsZSgiQmVmb3JlIGNjIGZpbHRlcmluZyIpICYKICAgICAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSBwbGFzbWEobiA9IDEwLCBkaXJlY3Rpb24gPSAtMSksIGxpbWl0cyA9IGMobWluX3RocmVzaG9sZCwgbWF4X3RocmVzaG9sZCkpCiAgICAgICAgICAsdGl0bGUgPSAiQmVmb3JlIENDIGZpbHRlcmluZyIsc3VidGl0bGVfbnVtID0gMykKCgpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgIEZlYXR1cmVQbG90KG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSArIGdndGl0bGUoIkFmdGVyIGNjIGZpbHRlcmluZyIpICYKICAgICAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSBwbGFzbWEobiA9IDEwLCBkaXJlY3Rpb24gPSAtMSksIGxpbWl0cyA9IGMobWluX3RocmVzaG9sZCwgbWF4X3RocmVzaG9sZCkpCiAgICAgICAgICAsdGl0bGUgPSAiQWZ0ZXIgQ0MgZmlsdGVyaW5nIiAsc3VidGl0bGVfbnVtID0gMykKCmBgYAojIyBERUcKCmBgYHtyIGZpZy53aWR0aD04LCBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnLGZpZy5rZWVwPSdhbGwnfQphbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkID0gU2V0SWRlbnQoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwgdmFsdWUgPSJwYXRpZW50LmlkZW50IikKYWNjX2RlZyA8LQogIEZpbmRNYXJrZXJzKAogICAgYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwKICAgIGlkZW50LjEgPSAiSE1TQyIsCiAgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCksCiAgICBkZW5zaWZ5ID0gVCwKICAgIHZlcmJvc2UgPSBULAogICAgc2xvdCA9ICJkYXRhIiwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4obG9nKHJvd01lYW5zKHgpICsgMSxiYXNlID0gMikpICMgY2hhbmdlIGZ1bmMgdG8gY2FsY3VsYXRlIGxvZ0ZDIGluIGxvZyBzcGFjZSBkYXRhIChkZWZhdWx0IHRvIGV4cG9uZW50IGRhdGEpCiAgICB9LAogICAgYXNzYXkgPSAiUk5BIgogICkKYGBgCgoKYGBge3J9CnByaW50X3RhYihwbHQgPSBlbnJpY2htZW50X2FuYWx5c2lzKGFjY19kZWcsYmFja2dyb3VuZCA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCksZmRyX0N1dG9mZiA9IDAuMDEsaWRlbnQuMSA9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhNU0MiLGlkZW50LjIgPSAiQUNDIixzaG93X2J5ID0gMSkKICAgICAgICAgICx0aXRsZSA9ICJFbnJpY2htZW50IGFmdGVyIGZpbHRlcmluZyIsc3VidGl0bGVfbnVtID0gMykKYGBgCgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTMsIHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KGh5cGVSKQpnZW5lc2V0cyA8LSBtc2lnZGJfZG93bmxvYWQoIkhvbW8gc2FwaWVucyIsY2F0ZWdvcnk9IkgiKSAlPiUgYXBwZW5kKCBtc2lnZGJfZG93bmxvYWQoIkhvbW8gc2FwaWVucyIsY2F0ZWdvcnk9IkMyIixzdWJjYXRlZ29yeSA9ICJDUDpLRUdHIikpCnJhbmtlZF92ZWMgPSBhY2NfZGVnWywiYXZnX2xvZzJGQyJdJT4lIHNldE5hbWVzKHJvd25hbWVzKGFjY19kZWcpKSAlPiUgbmEub21pdCgpICMgbWFrZSBuYW1lZCB2ZWN0b3IKCmh5cF9vYmogPC1oeXBlUl9mZ3NlYShzaWduYXR1cmUgPSByYW5rZWRfdmVjLGdlbmVzZXRzID0gZ2VuZXNldHMsdXBfb25seSA9IEYpCgpwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikKcGx0MSA9IHBsdCR1cCsgYWVzKHNpemU9bmVzKStnZ3RpdGxlKCJ1cCBpbiBITVNDIikKcGx0MiA9IHBsdCRkbisgYWVzKHNpemU9YWJzKG5lcykpK2dndGl0bGUoInVwIGluIEFDQyIpCnBsdDMgPSBwbHQxK3BsdDIKcGx0MwpgYGAKCgpgYGB7cn0KcGRmKGZpbGUgPSAiLi9GaWd1cmVzL0FDQ192c19ITVNDX0dTRUEucGRmIix3aWR0aCA9IDEzLGhlaWdodCA9IDYpCnBsdDMKZGV2Lm9mZigpCmBgYAoKYGBge3J9CnZvbGNhbm9fcGxvdChkZV9nZW5lcyA9IGFjY19kZWcsZmRyX2N1dG9mZiA9IDAuMDUsZmNfY3V0b2ZmID0gMiwgaWRlbnQxID0gIkhNU0MiLGlkZW50MiA9ICJBQ0MiLHRvcF9nZW5lc190ZXh0ID0gNCkKYGBgCmBgYHtyIGZpZy53aWR0aD04LCBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnLGZpZy5rZWVwPSdhbGwnfQphbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkID0gU2V0SWRlbnQoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwgdmFsdWUgPSJwYXRpZW50LmlkZW50IikKYWNjX2RlZyA8LQogIEZpbmRNYXJrZXJzKAogICAgYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwKICAgIGlkZW50LjEgPSAiSE1TQyIsCiAgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCksCiAgICBkZW5zaWZ5ID0gVCwKICAgIHZlcmJvc2UgPSBULAogICAgc2xvdCA9ICJkYXRhIiwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4ocm93TWVhbnMoeCkgKyAxKSAjIGNoYW5nZSBmdW5jIHRvIGNhbGN1bGF0ZSBsb2dGQyBpbiBsb2cgc3BhY2UgZGF0YSAoZGVmYXVsdCB0byBleHBvbmVudCBkYXRhKQogICAgfSwKICAgIGFzc2F5ID0gIlJOQSIKICApCmBgYAoKCmBgYHtyfQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZkcl9jdXRvZmYgPSAwLjA1LGZjX2N1dG9mZiA9IDIsIGlkZW50MSA9ICJITVNDIixpZGVudDIgPSAiQUNDIix0b3BfZ2VuZXNfdGV4dCA9IDQpK3hsYWIoImF2ZyBkaWZmIikKYGBgCgoKCgpgYGB7cn0KcGRmKCIuL0ZpZ3VyZXMvdm9sY2Fub19wbG90X0FDQ19WU19ITVNDLnBkZiIpCnZvbGNhbm9fcGxvdChkZV9nZW5lcyA9IGFjY19kZWcsZmRyX2N1dG9mZiA9IDAuMDUsaWRlbnQxID0gIkhNU0MiLGlkZW50MiA9ICJBQ0MiLHRvcF9nZW5lc190ZXh0ID0gMyxsb2cyZmNfY3V0b2ZmID0gMC41KQpkZXYub2ZmKCkKCnBkZigiLi9GaWd1cmVzL0VucmljaG1lbnRfYW5hbHlzaXNfQUNDX1ZTX0hNU0MucGRmIikKZW5yaWNobWVudF9hbmFseXNpcyhhY2NfZGVnLGJhY2tncm91bmQgPSBWYXJpYWJsZUZlYXR1cmVzKGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQpLGZkcl9DdXRvZmYgPSAwLjAxLGlkZW50LjEgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJITVNDIixpZGVudC4yID0gIkFDQyIsc2hvd19ieSA9IDEpCmRldi5vZmYoKQoKYGBgCgoKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTh9CnRvcF9obXNjX2dlbmVzID0gYWNjX2RlZyAlPiUgZHBseXI6OmZpbHRlcihhdmdfbG9nMkZDID4gMCkgJT4lICBzbGljZV9taW4obiA9IDEwLG9yZGVyX2J5ID0gcF92YWxfYWRqKSAlPiUgcm93bmFtZXMoKQp0b3BfYWNjX2dlbmVzID0gYWNjX2RlZyAlPiUgZHBseXI6OmZpbHRlcihhdmdfbG9nMkZDIDwgMCkgJT4lICBzbGljZV9taW4obiA9IDEwLG9yZGVyX2J5ID0gcF92YWxfYWRqKSAlPiUgcm93bmFtZXMoKQphbGxfdG9wX2RlZyA9IGModG9wX2htc2NfZ2VuZXMsdG9wX2FjY19nZW5lcykKCmFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQkY2FuY2VyX3R5cGUgPSBhbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkJHBhdGllbnQuaWRlbnQgJT4lIGdzdWIocGF0dGVybiA9ICJBQ0MuKiIscmVwbGFjZW1lbnQgPSAiQUNDIikKY2FuY2VyX3R5cGUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwgdmFycyA9ICJjYW5jZXJfdHlwZSIpCiMgY29sX2xpc3QgPSBsaXN0KGNpcmNsaXplOjpjb2xvclJhbXAyKGMoMCwgMSksIGMoIndoaXRlIiwgInJlZCIpKSk7IG5hbWVzKGNvbF9saXN0KSA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldCmNvbHVtbl9oYSA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gY2FuY2VyX3R5cGUpCgpkYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsdmFycyA9IGFsbF90b3BfZGVnLHNsb3QgPSAic2NhbGUuZGF0YSIpICU+JSB0KCkKCnByaW50KENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKGRhdGEsc2hvd19jb2x1bW5fbmFtZXMgPSBGLHJvd19uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSA3KSxjbHVzdGVyX3Jvd3MgPSBGLCAsbmFtZSA9ICJaLXNjb3JlIGV4cHJlc3Npb24iLGNsdXN0ZXJfY29sdW1ucyA9IEYsdG9wX2Fubm90YXRpb24gPSBjb2x1bW5faGEpKQogIAoKYGBgCgoKCgoKCgoKIyMgQ05WIHBsb3Qgey50YWJzZXR9CmBgYHtyfQojIGNyZWF0ZSBleHByZXNzaW9uIG1hdHJpeCBvZiBhY2MgKyBub3JtYWwgY2VsbHMgKyBITVNDIHNldXJhdCBpbnRlZ3JhdGVkCmFjY19hbGxfY2VsbHNfbm9BY2MxID0gc3Vic2V0KGFjY19hbGxfY2VsbHMsIHN1YnNldCA9IHBhdGllbnQuaWRlbnQgIT0gIkFDQzEiKQphY2NfZXhwciA9IGFjY19hbGxfY2VsbHNfbm9BY2MxQGFzc2F5cyRSTkFAZGF0YSAlPiUgYXMuZGF0YS5mcmFtZSgpCmhtc2NfZXhwciAgPSBhY2MuY29tYmluZWRAYXNzYXlzJGludGVncmF0ZWRAZGF0YSAlPiUgYXMuZGF0YS5mcmFtZSgpCmFjY19leHByID0gYWNjX2V4cHIgWyByb3duYW1lcyhobXNjX2V4cHIpLF0KYWxsX2V4cHIgPSBjYmluZChhY2NfZXhwcixobXNjX2V4cHIpCgojIGNyZWF0ZSBhbm5vdGF0aW9uIAphY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkICA9IGFzLmRhdGEuZnJhbWUoYWNjX2FsbF9jZWxsc0BtZXRhLmRhdGFbLCJjZWxsLnR5cGUiLGRyb3AgPSBGXSkKYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZCA9IGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWRbY29sbmFtZXMoYWxsX2V4cHIpLCxkcm9wID0gRl0KYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZCA9IGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigib3JpZy5pZGVudCIpIAoKIyAjd3JpdGUgZXhwcmVzc2lvbiBhbmQgYW5ub3RhdGlvbgojIHdyaXRlLnRhYmxlKGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQsICIuL0RhdGEvaW5mZXJDTlYvYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZC50eHQiLCBhcHBlbmQgPSBGQUxTRSwgCiMgICAgICAgICAgICAgc2VwID0gIlx0IiwgZGVjID0gIi4iLHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGKQojIAojIAojIHdyaXRlLnRhYmxlKGFsbF9leHByLCAiLi9EYXRhL2luZmVyQ05WL2FsbC40aWNudl9pbnRlZ3JhdGVkLnR4dCIsIGFwcGVuZCA9IEZBTFNFLCAKIyAgICAgICAgICAgICBzZXAgPSAiXHQiLCBkZWMgPSAiLiIscm93Lm5hbWVzID0gVCwgY29sLm5hbWVzID0gVCkKYGBgCgpgYGB7cn0KdHJhY2UoaW5mZXJjbnY6OnJ1bixlZGl0ID0gVCkgIyB0byBza2lwIG5vcm1hbGl6YXRpb24sIGNoYW5nZSB0byBza2lwX3Bhc3QgPSA0IChodHRwczovL2dpdGh1Yi5jb20vYnJvYWRpbnN0aXR1dGUvaW5mZXJjbnYvaXNzdWVzLzM0NikKYGBgCgpgYGB7cn0KCmluZmVyY252X29iaiA9IENyZWF0ZUluZmVyY252T2JqZWN0KHJhd19jb3VudHNfbWF0cml4PSIuL0RhdGEvaW5mZXJDTlYvYWxsLjRpY252X2ludGVncmF0ZWQudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25zX2ZpbGU9Ii4vRGF0YS9pbmZlckNOVi9hY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkLnR4dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGltPSJcdCIsZ2VuZV9vcmRlcl9maWxlPSIuL0RhdGEvaW5mZXJDTlYvZ2VuY29kZV92MTlfZ2VuZV9wb3MudHh0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAscmVmX2dyb3VwX25hbWVzPWMoIkNBRiIsICJFbmRvdGhlbGlhbCIsICJXQkMiKSkgI2dyb3VwcyBvZiBub3JtYWwgY2VsbHMKCmluZmVyY252X29ial9kZWZhdWx0ID0gaW5mZXJjbnY6OnJ1bihpbmZlcmNudl9vYmosIGN1dG9mZj0xLCBvdXRfZGlyPScuL0RhdGEvaW5mZXJDTlYvaW5mZXJjbnZfaW50ZXJncmF0ZWRfb3V0cHV0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfYnlfZ3JvdXBzPVQsIHBsb3Rfc3RlcHM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZW5vaXNlPVRSVUUsIEhNTT1GQUxTRSwgbm9fcHJlbGltX3Bsb3Q9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBuZ19yZXM9MzAwKQp1bnRyYWNlKGluZmVyY252OjpydW4pCgoKYGBgCgoKYGBge3J9CnRyYWNlKGluZmVyY252Ojo6Z2V0X2dyb3VwX2NvbG9yX3BhbGV0dGUgLGVkaXQgPSBUKSAjIGNoYW5nZSAiU2V0MyIgdG8gIlNldDEiIGZvciBtb3JlIGRpc3Rpbmd1aXNoYWJsZSBjb2xvcnMKcGxvdF9jbnYoaW5mZXJjbnZfb2JqX2RlZmF1bHQsIG91dHB1dF9mb3JtYXQgPSAicG5nIiwgIHdyaXRlX2V4cHJfbWF0cml4ID0gRkFMU0Usb3V0X2RpciA9ICIuL0RhdGEvaW5mZXJDTlYvaW5mZXJjbnZfaW50ZXJncmF0ZWRfb3V0cHV0IixwbmdfcmVzCT04MDAsb2JzX3RpdGxlID0gIk1hbGlnbmFudCBjZWxscyIscmVmX3RpdGxlID0gIk5vcm1hbCBjZWxscyIsY29udGlnX2NleCA9IDIsIHRpdGxlID0gIkNvcHkgbnVtYmVyIHZhcmlhdGlvbiIpCnVudHJhY2UoaW5mZXJjbnY6OjpnZXRfZ3JvdXBfY29sb3JfcGFsZXR0ZSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LHJlc3VsdHM9J2FzaXMnfQpwcmludF90YWIocGx0ID0ga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi4vRGF0YS9pbmZlckNOVi9pbmZlcmNudl9pbnRlcmdyYXRlZF9vdXRwdXQvaW5mZXJjbnYucG5nIikKICAgICAgICAgICx0aXRsZSA9ICJDTlYgcGxvdCIsc3VidGl0bGVfbnVtID0gMykKYGBgCgoKYGBge3IscmVzdWx0cz0nYXNpcyd9CmxpYnJhcnkobGltbWEpCnNtb290aGVkPWFwcGx5KGluZmVyY252X29ial9kZWZhdWx0QGV4cHIuZGF0YSwyLHRyaWN1YmVNb3ZpbmdBdmVyYWdlLCBzcGFuPTAuMDEpCmNuc2lnPXNxcnQoYXBwbHkoKHNtb290aGVkLTEpXjIsMixtZWFuKSkKCmFjY19hbGxfY2VsbHMgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjX2FsbF9jZWxscywgbWV0YWRhdGEgPSBjbnNpZywgY29sLm5hbWUgPSAiY29weW51bWJlciIpCmFjY19hbGxfY2VsbHMgPSBTZXRJZGVudChvYmplY3QgPSBhY2NfYWxsX2NlbGxzLHZhbHVlID0gImNlbGwudHlwZSIpCgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3QoYWNjX2FsbF9jZWxscywgImNvcHludW1iZXIiLHB0LnNpemUgPSAxLGxhYmVsID0gVCxyZXBlbCA9IFQpKwogICAgICAgICAgICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9Yygid2hpdGUiLCJsaWdodGJsdWUiLCJvcmFuZ2UiLCJyZWQiLCJkYXJrcmVkIikpCiAgICAgICAgICAsdGl0bGUgPSAiQ05WIFVNQVAiLHN1YnRpdGxlX251bSA9IDMpCgpgYGAKCgoKCiMgSE1TQyBhbmFseXNpcyAKIyMgVU1BUCAKYGBge3J9CmFjYzFfY2FuY2VyX2NlbGxzID0gRmluZENsdXN0ZXJzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZlcmJvc2UgPSBGLHJlc29sdXRpb24gPSAwLjUpCkRpbVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMscHQuc2l6ZSA9IDIpCmBgYAoKIyMgU2NvcmVzIApgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjKCJNWUIiLCJKQUcxIikscHQuc2l6ZSA9IDIpKwpEaW1QbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGdyb3VwLmJ5ICA9IGMoImhwdjMzX3Bvc2l0aXZlIikscHQuc2l6ZSA9IDIpCgpgYGAKCiMjIERFRyB7LnRhYnNldH0KYGBge3IgcmVzdWx0cz0nYXNpcyd9ClNldElkZW50KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhbHVlID0gInNldXJhdF9jbHVzdGVycyIpCmRlZyA9IEZpbmRBbGxNYXJrZXJzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyksZGVuc2lmeSA9IFQsdmVyYm9zZSA9IEYpCmZvciAoY2x1c3RlciBpbiB1bmlxdWUoZGVnJGNsdXN0ZXIpKSB7CiAgcHJpbnRfdGFiKHBsdCA9IGRlZ1tkZWckY2x1c3RlciA9PSBjbHVzdGVyLF0sdGl0bGUgPSAiREVHIiAsc3VidGl0bGVfbnVtID0gdG9jX3RhYnNfbGV2ZWwpCn0KYGBgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KZm9yIChjbHVzdGVyIGluIHVuaXF1ZShkZWckY2x1c3RlcikpIHsKICBkZWdfb2ZfY2x1c3RlciA9IGRlZ1tkZWckY2x1c3RlciA9PSBjbHVzdGVyLF0gCiAgIyAgcHJpbnQoZGVnX29mX2NsdXN0ZXIgJWluJSBvcmlnaW5hbF9teW9fZ2VuZXMgJT4lIHdoaWNoKCkpCiAgIyBwcmludChkZWdfb2ZfY2x1c3RlciAlaW4lIG9yaWdpbmFsX2x1bV9nZW5lcyAlPiUgd2hpY2goKSkKICBwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgZW5yaWNobWVudF9hbmFseXNpcyhkZWdfb2ZfY2x1c3RlcixiYWNrZ3JvdW5kID1WYXJpYWJsZUZlYXR1cmVzKGFjYzFfY2FuY2VyX2NlbGxzKSxmZHJfQ3V0b2ZmID0gMC4wMSxpZGVudC4xID0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiQ2x1c3RlciIsY2x1c3RlciksaWRlbnQuMiA9ICBwYXN0ZSgiQ2x1c3RlciIsY2x1c3Rlciksc2hvd19ieSA9IDEpCiAgICAgICAgICAgICx0aXRsZSA9IGNsdXN0ZXIsc3VidGl0bGVfbnVtID0gdG9jX3RhYnNfbGV2ZWwpCn0KCgpgYGAKCgojIyBOTUYgey50YWJzZXR9CmBgYHtweXRob259CmZyb20gY25tZiBpbXBvcnQgY05NRgppbXBvcnQgcGlja2xlCm5mZWF0dXJlcyA9ICIySyIKZiA9IG9wZW4oJy4vRGF0YS9jTk1GL0hNU0NfY05NRl9oYXJtb255XzJLdmFyZ2VuZXMvY25tZl9vYmoucGNrbCcsICdyYicpCmNubWZfb2JqID0gcGlja2xlLmxvYWQoZikKZi5jbG9zZSgpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIuL0RhdGEvY05NRi9ITVNDX2NOTUZfaGFybW9ueV8yS3ZhcmdlbmVzL0hNU0NfY05NRl9oYXJtb255XzJLdmFyZ2VuZXMua19zZWxlY3Rpb24ucG5nIikKYGBgCgpgYGB7cHl0aG9ufQpzZWxlY3RlZF9rID0gMwpkZW5zaXR5X3RocmVzaG9sZCA9IDAuMQpjbm1mX29iai5jb25zZW5zdXMoaz1zZWxlY3RlZF9rLCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCxzaG93X2NsdXN0ZXJpbmc9VHJ1ZSkKdXNhZ2Vfbm9ybSwgZ2VwX3Njb3JlcywgZ2VwX3RwbSwgdG9wZ2VuZXMgPSBjbm1mX29iai5sb2FkX3Jlc3VsdHMoSz1zZWxlY3RlZF9rLCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCkKYGBgCgpgYGB7cn0KZ2VwX3Njb3JlcyA9IHB5JGdlcF9zY29yZXMKZ2VwX3RwbSA9IHB5JGdlcF90cG0KYWxsX21ldGFnZW5lcz0gcHkkdXNhZ2Vfbm9ybQpgYGAKCiMjIEhhcm1vbnkgcmVzdWx0cyB7LnRhYnNldH0KCgoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KIyBNYWtlIG1ldGFnZW5lIG5hbWVzCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKVtpXSA9ICJtZXRhZ2VuZS4iICU+JSBwYXN0ZTAoaSkKfQoKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBtZXRhZ2VfbWV0YWRhdGEgPSBhbGxfbWV0YWdlbmVzICU+JSBzZWxlY3QoaSkKICBhY2MxX2NhbmNlcl9jZWxscyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gbWV0YWdlX21ldGFkYXRhKQp9CnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSxjb21iaW5lID0gVCksCiAgICAgICAgICB0aXRsZSA9ICJtZXRhZ2VuZXMgZXhwcmVzc2lvbiIsc3VidGl0bGVfbnVtID0gdG9jX3RhYnNfbGV2ZWwpCgojYWRkIGVhY2ggbWV0YWdlbmUgdG8gbWV0YWRhdGEKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIG1ldGFnZV9tZXRhZGF0YSA9IGFsbF9tZXRhZ2VuZXMgJT4lIHNlbGVjdChpKQogIGx1bmdfY29ycl9ub25uZWcgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBsdW5nX2NvcnJfbm9ubmVnLG1ldGFkYXRhID0gbWV0YWdlX21ldGFkYXRhKQp9CnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRmVhdHVyZVBsb3Qob2JqZWN0ID0gbHVuZ19jb3JyX25vbm5lZyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLGNvbWJpbmUgPSBUKSwKICAgICAgICAgIHRpdGxlID0gIm1ldGFnZW5lcyBleHByZXNzaW9uIixzdWJ0aXRsZV9udW0gPSB0b2NfdGFic19sZXZlbCkKYGBgCgoKIyMgRW5yaWNobWVudCBhbmFseXNpcyBieSB0b3AgMjAwIGdlbmVzIG9mIGVhY2ggcHJvZ3JhbQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCByZXN1bHRzPSdoaWRlJ30KCiMgY2Fub25pY2FsX3BhdGh3YXlzID0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIsIGNhdGVnb3J5ID0gIkMyIikgJT4lIGRwbHlyOjpmaWx0ZXIoZ3Nfc3ViY2F0ICE9ICJDR1AiKSAlPiUgIGRwbHlyOjpkaXN0aW5jdChnc19uYW1lLCBnZW5lX3N5bWJvbCkgCgpwbHRfbGlzdCA9IGxpc3QoKQpmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksMjAwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzID0gY2Fub25pY2FsX3BhdGh3YXlzKQogICAKICBwbHRfbGlzdFtbaV1dID0gcmVzJHBsdAp9CmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyb2JzID0gcGx0X2xpc3QpCmBgYAoKYGBge3J9CmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICByYW5rZWRfdmVjID0gZ2VwX3Njb3JlcyAlPiUgcHVsbChpKSAlPiUgIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXMpKQogIGh5cF9vYmogPC1oeXBlUl9mZ3NlYShzaWduYXR1cmUgPSByYW5rZWRfdmVjLGdlbmVzZXRzID0gZ2VuZXNldHMsdXBfb25seSA9IFQpCgogIHBsdCA9IGh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKSsgYWVzKHNpemU9YWJzKG5lcykpCiAgcHJpbnQocGx0KQp9CmBgYApgYGB7cn0KZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogICMgZ2VwX3Njb3JlcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAKICByYW5rZWRfdmVjID0gZ2VwX3Njb3JlcyAlPiUgcHVsbChpKSAlPiUgIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXMpKQogIGh5cF9vYmogPC1oeXBlUl9mZ3NlYShzaWduYXR1cmUgPSByYW5rZWRfdmVjLGdlbmVzZXRzID0gZ2VuZXNldHMsdXBfb25seSA9IFQpCgogIHBsdCA9IGh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKQogIHByaW50KHBsdCkKfQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTB9CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmFjYzFfY2FuY2VyX2NlbGxzID0gU2V0SWRlbnQob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFsdWUgPSAic2V1cmF0X2NsdXN0ZXJzIikKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDUwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIGRhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IHRvcCklPiUgc2NhbGUoKSAlPiUgdCgpIAogIG1ldGFnZW5lX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldKQogIGNvbF9saXN0ID0gbGlzdChjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKDAsIDEpLCBjKCJ3aGl0ZSIsICJyZWQiKSkpOyBuYW1lcyhjb2xfbGlzdCkgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKVtpXQogIGNvbHVtbl9oYSA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gbWV0YWdlbmVfZGF0YSxjb2wgPSBjb2xfbGlzdCkKICBwZGYocGFzdGUwKCIuL0ZpZ3VyZXMvTk1GX3RvcF9nZW5lc19wcm9ncmFtIixpLCIucGRmIikpCiAgcHJpbnQoQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAoZGF0YSxzaG93X2NvbHVtbl9uYW1lcyA9IEYscm93X25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDcpLGNsdXN0ZXJfcm93cyA9IEYsIHRvcF9hbm5vdGF0aW9uID0gY29sdW1uX2hhLG5hbWUgPSAiWi1zY29yZSBleHByZXNzaW9uIikpCiAgZGV2Lm9mZigpCn0KCmBgYAoKYGBge3J9CgpgYGAKCgoKCiMjIEx1bSBNeW8gc2NvcmUKCmBgYHtyfQpvcmlnaW5hbF9teW9fZ2VuZXMgPSBjKCAiVFA2MyIsICJUUDczIiwgIkNBVjEiLCAiQ0RIMyIsICJLUlQ1IiwgIktSVDE0IiwgIkFDVEEyIiwgIlRBR0xOIiwgIk1ZTEsiLCAiREtLMyIpCm9yaWdpbmFsX2x1bV9nZW5lcyA9IGMoIktJVCIsICJFSEYiLCAiRUxGNSIsICJLUlQ3IiwgIkNMRE4zIiwgIkNMRE40IiwgIkNEMjQiLCAiTEdBTFMzIiwgIkxDTjIiLCAiU0xQSSIgKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpGZWF0dXJlUGxvdChhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IG9yaWdpbmFsX215b19nZW5lcykKRmVhdHVyZVBsb3QoYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBvcmlnaW5hbF9sdW1fZ2VuZXMpCgpgYGAKCgpgYGB7cn0KYWxsX2FjY19jYW5jZXJfY2VsbHMgPSBTZXRJZGVudChhbGxfYWNjX2NhbmNlcl9jZWxscyx2YWx1ZSA9ICJwYXRpZW50LmlkZW50IikKY2FsY3VsYXRlX3Njb3JlKGRhdGFzZXQgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyxteW9fZ2VuZXMgPSBvcmlnaW5hbF9teW9fZ2VuZXMsbHVtX2dlbmVzID0gb3JpZ2luYWxfbHVtX2dlbmVzKQpgYGAKYGBge3J9Cm15b19leHByID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKG9yaWdpbmFsX215b19nZW5lcykpCm15b19jb3IgPSBjb3IobXlvX2V4cHIpCnBoZWF0bWFwKG15b19jb3IpCgpteW9fZXhwciA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYyhvcmlnaW5hbF9sdW1fZ2VuZXMpKQpteW9fY29yID0gY29yKG15b19leHByKQpwaGVhdG1hcChteW9fY29yKQoKbXlvX2V4cHIgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSx2YXJzID0gYyhvcmlnaW5hbF9teW9fZ2VuZXMpKQpteW9fY29yID0gY29yKG15b19leHByKQpwaGVhdG1hcChteW9fY29yKQoKbXlvX2V4cHIgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSx2YXJzID0gYyh0b3BfbHVtLGx1bSkpCm15b19jb3IgPSBjb3IobXlvX2V4cHIpCnBoZWF0bWFwKG15b19jb3IpCmBgYAoKIyMgT3JpZ2luYWwgc2NvcmUgb2YgQUNDMQpgYGB7cn0KbHVtID0gYygiTENOMiIsIkNMRE4zIiwiRUxGNSIsIk1NUDciLCAiR0FCUlAiLCJDQUxNTDUiLCJFRk5BNSIpCm15byA9IG15b19lbnJpY2hlZF9nZW5lcwpgYGAKCgpgYGB7cn0KdHJhY2UoY2FsY3VsYXRlX3Njb3JlLCBlZGl0ID0gVCkKYGBgCgpgYGB7cn0KY2FsY3VsYXRlX3Njb3JlKGRhdGFzZXQgPSBhY2MxX2NhbmNlcl9jZWxscyxteW9fZ2VuZXMgPSBvcmlnaW5hbF9teW9fZ2VuZXMsbHVtX2dlbmVzID0gb3JpZ2luYWxfbHVtX2dlbmVzLGx1bV90aHJlc2hvbGQgPSAwLG15b190aHJlc2hvbGQgPSAwKQpgYGAKCgpgYGB7cn0KY2RfZmVhdHVyZXMgPC0gbGlzdChvcmlnaW5hbF9teW9fZ2VuZXMpCmFjYzFfY2FuY2VyX2NlbGxzIDwtIEFkZE1vZHVsZVNjb3JlKAogIG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLAogIGZlYXR1cmVzID0gY2RfZmVhdHVyZXMsCiAgY3RybCA9IDUsCiAgbmFtZSA9ICdteW9fRmVhdHVyZXMnCikKCkZlYXR1cmVQbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gIm15b19GZWF0dXJlczEiKQpgYGAKCmBgYHtyfQpjZF9mZWF0dXJlcyA8LSBsaXN0KGMoIktSVDciLCAgICJMR0FMUzMiICwiTENOMiIgICwgIlNMUEkiKSkKYWNjMV9jYW5jZXJfY2VsbHMgPC0gQWRkTW9kdWxlU2NvcmUoCiAgb2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsCiAgZmVhdHVyZXMgPSBjZF9mZWF0dXJlcywKICBjdHJsID0gNSwKICBuYW1lID0gJ2x1bV9GZWF0dXJlcycKKQoKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSAibHVtX0ZlYXR1cmVzMSIpCmBgYAogCmBgYHtyfQpjb3IoYWNjMV9jYW5jZXJfY2VsbHMkbHVtX0Zlb3JpZ2luYWxfbXlvX2dlbmVzYXR1cmVzMSxhY2MxX2NhbmNlcl9jZWxscyRteW9fRmVhdHVyZXMxKQpgYGAKCiMjIyBNeW8gZ2VuZXMKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIGNvbGxhcHNlPVR9Cm15b19wcm90ZWluX21hcmtlcnMgPSBjKCJDTk4xIiwgIlRQNjMiLCJBQ1RBMiIpCnRvcF9teW8gID0gdG9wX2NvcnJlbGF0ZWQoZGF0YXNldCA9IGFjYzFfY2FuY2VyX2NlbGxzLCBnZW5lcyA9IG15b19wcm90ZWluX21hcmtlcnMsdGhyZXNob2xkID0gMC4zNSkKcHJpbnQoIk51bWJlciBvZiBnZW5lcyA9ICIgJT4lIHBhc3RlKGxlbmd0aCh0b3BfbXlvKSkpCm1lc3NhZ2UoIk5hbWVzIG9mIGdlbmVzOiIpCnRvcF9teW8gJT4lIGhlYWQoMzApCm1lc3NhZ2UoIkdlbmVzIHRoYXQgYWxzbyBhcGVhcmVkIGluIHRoZSBvcmlnaW5hbCBzY29yZToiKQpiYXNlOjppbnRlcnNlY3QodG9wX215byxvcmlnaW5hbF9teW9fZ2VuZXMpIApgYGAKCgoKYGBge3J9Cm15b19lbnJpY2hfcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3BfbXlvLGJhY2tncm91bmQgPSByb3duYW1lcyhhY2MxX2NhbmNlcl9jZWxscyksaG9tZXIgPSBULHRpdGxlID0gIm15byB0b3AgZW5yaWNobWVudCIsY3VzdG9tX3BhdGh3YXlzID0gbHVtaW5hbF9ncykKbXlvX2VucmljaF9yZXMKYGBgCiMjIyBMdW0gZ2VuZXMKYGBge3J9Cmx1bV9wcm90ZWluX21hcmtlcnMgPSBjKCJLSVQiKQp0b3BfbHVtICA9IHRvcF9jb3JyZWxhdGVkKGRhdGFzZXQgPSBhY2MxX2NhbmNlcl9jZWxscywgZ2VuZXMgPSBsdW1fcHJvdGVpbl9tYXJrZXJzLHRocmVzaG9sZCA9IDAuMzAsbl92YXJnZW5lcyA9IDUwMDApCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgPSAiICU+JSBwYXN0ZShsZW5ndGgodG9wX2x1bSkpKQptZXNzYWdlKCJOYW1lcyBvZiBnZW5lczoiKQp0b3BfbHVtICU+JSBoZWFkKDMwKQptZXNzYWdlKCJHZW5lcyB0aGF0IGFsc28gYXBlYXJlZCBpbiB0aGUgb3JpZ2luYWwgc2NvcmU6IikKYmFzZTo6aW50ZXJzZWN0KHRvcF9sdW0sb3JpZ2luYWxfbHVtX2dlbmVzKSAKYGBgCgpgYGB7cn0KbHVtX2VucmljaF9yZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcF9sdW0sYmFja2dyb3VuZCA9IHJvd25hbWVzKGFjYzFfY2FuY2VyX2NlbGxzKSxob21lciA9IFQsdGl0bGUgPSAibHVtIHRvcCBlbnJpY2htZW50IixjdXN0b21fcGF0aHdheXMgPSBsdW1pbmFsX2dzKQpsdW1fZW5yaWNoX3JlcwpgYGAKCmBgYHtyfQpyb3duYW1lcyhteW9fZW5yaWNoX3JlcykgPSBteW9fZW5yaWNoX3JlcyRwYXRod2F5X25hbWUKbXlvX2VucmljaGVkX2dlbmVzID0gbXlvX2VucmljaF9yZXNbMSwiZ2VuZUlEIl0gJT4lIHN0cnNwbGl0KHNwbGl0ID0gIi8iKSAlPiUgLltbMV1dICU+JSBjKC4sbXlvX3Byb3RlaW5fbWFya2VycykgI2FkZCBvcmlnaW5hbCBtYXJrZXJzCm15b3Njb3JlPUZldGNoRGF0YShvYmplY3QgPWFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSAgbXlvX2VucmljaGVkX2dlbmVzLHNsb3QgPSAiZGF0YSIpICU+JSByb3dNZWFucygpCmFjYzFfY2FuY2VyX2NlbGxzPUFkZE1ldGFEYXRhKGFjYzFfY2FuY2VyX2NlbGxzLG15b3Njb3JlLCJteW9fc2NvcmUiKQoKCm15b3Njb3JlPUZldGNoRGF0YShvYmplY3QgPWFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSAgdG9wX215byxzbG90ID0gImRhdGEiKSAlPiUgcm93TWVhbnMoKQphY2MxX2NhbmNlcl9jZWxscz1BZGRNZXRhRGF0YShhY2MxX2NhbmNlcl9jZWxscyxteW9zY29yZSwibXlvX3Njb3JlIikKYGBgCgoKIyMgSFBWCiMjIyBIUFYgVU1BUAoKYGBge3J9CkhQVjMzX1AzID0gZnJlYWQoIi4vRGF0YS9IUFYzM19QMy50eHQiLGNvbC5uYW1lcyA9IGMoInBsYXRlIiwicmVhZHMiKSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpIUFYzM19QMy5kZiA9IEhQVjMzX1AzICU+JSBtdXRhdGUoCiAgcGxhdGUgPSBnc3ViKHggPUhQVjMzX1AzJHBsYXRlLCByZXBsYWNlbWVudCA9ICIiLHBhdHRlcm4gPSAiXy4qJCIpIAogICU+JSBnc3ViKHBhdHRlcm4gPSAiLVAiLHJlcGxhY2VtZW50ID0gIi5QIikgCiAgJT4lIGdzdWIocGF0dGVybiA9ICItIixyZXBsYWNlbWVudCA9ICJfIiwpCiAgKQpIUFYzM19QMy5kZiA9IEhQVjMzX1AzLmRmICU+JSBkcGx5cjo6ZmlsdGVyKEhQVjMzX1AzLmRmJHBsYXRlICVpbiUgY29sbmFtZXMoYWNjMV9jYW5jZXJfY2VsbHMpKQpyb3duYW1lcyhIUFYzM19QMy5kZikgIDwtIEhQVjMzX1AzLmRmJHBsYXRlCkhQVjMzX1AzLmRmJHBsYXRlID0gTlVMTAoKCkhQVjMzX1AyID0gZnJlYWQoIi4vRGF0YS9IUFYzM19QMi50eHQiLGNvbC5uYW1lcyA9IGMoInBsYXRlIiwicmVhZHMiKSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpIUFYzM19QMi5kZiA9IEhQVjMzX1AyICU+JSBtdXRhdGUoCiAgcGxhdGUgPSBnc3ViKHggPUhQVjMzX1AyJHBsYXRlLCByZXBsYWNlbWVudCA9ICIiLHBhdHRlcm4gPSAiXy4qJCIpIAogICU+JSBnc3ViKHBhdHRlcm4gPSAicGxhdGUyLSIscmVwbGFjZW1lbnQgPSAicGxhdGUyXyIsKQogICU+JSBnc3ViKHBhdHRlcm4gPSAiLSIscmVwbGFjZW1lbnQgPSAiXFwuIiwpCiAgKQpIUFYzM19QMi5kZiA9IEhQVjMzX1AyLmRmICU+JSBkcGx5cjo6ZmlsdGVyKEhQVjMzX1AyLmRmJHBsYXRlICVpbiUgY29sbmFtZXMoYWNjMV9jYW5jZXJfY2VsbHMpKQpyb3duYW1lcyhIUFYzM19QMi5kZikgIDwtIEhQVjMzX1AyLmRmJHBsYXRlCkhQVjMzX1AyLmRmJHBsYXRlID0gTlVMTAoKSFBWMzMgPSByYmluZChIUFYzM19QMy5kZixIUFYzM19QMi5kZikKYWNjMV9jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IEhQVjMzLGNvbC5uYW1lID0gIkhQVjMzLnJlYWRzIikKRmVhdHVyZVBsb3QoYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSAiSFBWMzMucmVhZHMiLG1heC5jdXRvZmYgPSAxMCkKYGBgCgoKYGBge3J9CgpkYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSAiSFBWMzMucmVhZHMiKQoKZGF0YSA9IGRhdGEgJT4lIG11dGF0ZSgiMCByZWFkcyIgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IEhQVjMzLnJlYWRzID09IDAsdHJ1ZSA9IDEsZmFsc2UgPSAwKSkKZGF0YSA9IGRhdGEgJT4lIG11dGF0ZSgiMSByZWFkcyIgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IEhQVjMzLnJlYWRzID09IDEsdHJ1ZSA9IDEsZmFsc2UgPSAwKSkKZGF0YSA9IGRhdGEgJT4lIG11dGF0ZSgiMiByZWFkcyIgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IEhQVjMzLnJlYWRzID09IDIsdHJ1ZSA9IDEsZmFsc2UgPSAwKSkKZGF0YSA9IGRhdGEgJT4lIG11dGF0ZSgiMy0yMyByZWFkcyIgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IEhQVjMzLnJlYWRzID49MyAmSFBWMzMucmVhZHMgIDwyNCx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIyNCsgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFYzMy5yZWFkcyA+PTI0LHRydWUgPSAxLGZhbHNlID0gMCkpCmRhdGEgPSBjb2xTdW1zKGRhdGFbLDI6bmNvbChkYXRhKV0pICU+JSBhcy5kYXRhLmZyYW1lKCkKbmFtZXMoZGF0YSlbMV0gPSAiY291bnQiCmRhdGEgPSByb3duYW1lc190b19jb2x1bW4oZGF0YSx2YXIgPSAiYmluIikKZGF0YQpnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1mYWN0b3IoYmluLGxldmVscyA9IGMoIjAgcmVhZHMiLCIxIHJlYWRzIiwiMiByZWFkcyIsIjMtMjMgcmVhZHMiLCIyNCsgcmVhZHMiKSksIHk9Y291bnQpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSJzdGVlbGJsdWUiKSArIHhsYWIoIkhQViBSZWFkcyIpKyB0aGVtZV9taW5pbWFsKCkrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1jb3VudCksIHZqdXN0PS0wLjUsIGNvbG9yPSJibGFjayIsIHNpemU9My41KQpgYGAKCgpgYGB7cn0KaHB2MzNfcG9zaXRpdmUgPSBIUFYzMyAlPiUgZHBseXI6Om11dGF0ZShocHYzM19wb3NpdGl2ZSA9IGNhc2Vfd2hlbihyZWFkcyA+PSAxMCB+ICJwb3NpdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhZHMgPCAxMCB+ICJuZWdhdGl2ZSIpCikKCgoKaHB2MzNfcG9zaXRpdmUkcmVhZHMgPSBOVUxMCmFjYzFfY2FuY2VyX2NlbGxzID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsbWV0YWRhdGEgPSBocHYzM19wb3NpdGl2ZSkKYGBgCgpgYGB7cn0KRGltUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxncm91cC5ieSAgPSBjKCJocHYzM19wb3NpdGl2ZSIpLHB0LnNpemUgPSAyKQpgYGAKCgpgYGB7cn0KbGlicmFyeShiaW9tYVJ0KQplbnNlbWJsID0gdXNlRW5zZW1ibChiaW9tYXJ0PSJlbnNlbWJsIiwgZGF0YXNldD0iaHNhcGllbnNfZ2VuZV9lbnNlbWJsIikKYGBgCgoKYGBge3IgZmlnLndpZHRoPTgsIGVjaG89VFJVRSxyZXN1bHRzPSdoaWRlJyxmaWcua2VlcD0nYWxsJ30KCmxpYnJhcnkoImJpb21hUnQiKQptYXJ0IDwtIHVzZU1hcnQoYmlvbWFydD0iZW5zZW1ibCIsIGRhdGFzZXQ9ImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIpCmFsbF9jb2RpbmdfZ2VuZXMgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoICJoZ25jX3N5bWJvbCIpLCBmaWx0ZXJzID0gYygiYmlvdHlwZSIpLCB2YWx1ZXMgPSBsaXN0KGJpb3R5cGU9InByb3RlaW5fY29kaW5nIiksIG1hcnQgPSBtYXJ0KQogICAKYWNjMV9jYW5jZXJfY2VsbHMgPSBGaW5kVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyxuZmVhdHVyZXMgPSAxNTAwMCkKYWNjMV9jYW5jZXJfY2VsbHMgPSBTZXRJZGVudChhY2MxX2NhbmNlcl9jZWxscywgdmFsdWUgPSJocHYzM19wb3NpdGl2ZSIpCmZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscykgJT4lIGludGVyc2VjdChhbGxfY29kaW5nX2dlbmVzJGhnbmNfc3ltYm9sKQphY2NfZGVnIDwtIEZpbmRNYXJrZXJzKGFjYzFfY2FuY2VyX2NlbGxzLCBpZGVudC4xID0gInBvc2l0aXZlIixpZGVudC4yID0gIm5lZ2F0aXZlIixmZWF0dXJlcyA9IGZlYXR1cmVzLGRlbnNpZnkgPSBULGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsbWluLmRpZmYucGN0ID0gMCkKCiMgZW5yaWNobWVudF9hbmFseXNpcyhhY2NfZGVnLGJhY2tncm91bmQgPSBWYXJpYWJsZUZlYXR1cmVzKGFjYzFfY2FuY2VyX2NlbGxzKSxmZHJfQ3V0b2ZmID0gMC4wMSxpZGVudC4xID0gIkhNU0MiLGlkZW50LjIgPSAiQUNDIixzaG93X2J5ID0gMSkKYWNjX2RlZyRmZHI8LXAuYWRqdXN0KHAgPSBhcy52ZWN0b3IoYWNjX2RlZyRwX3ZhbCkgLG1ldGhvZCA9ICJmZHIiKQphY2NfZGVnW2MoIk1ZQiIsIkpBRzEiKSxdCmFjY19kZWcgJT4lIGhlYWQoKQpnZW5lZGVzYyA8LSBnZXRCTShhdHRyaWJ1dGVzPWMoJ2V4dGVybmFsX2dlbmVfbmFtZScsJ2Rlc2NyaXB0aW9uJyksIGZpbHRlcnMgPSAnZXh0ZXJuYWxfZ2VuZV9uYW1lJywgdmFsdWVzID0gYWNjX2RlZyAlPiUgcm93bmFtZXMoKSwgbWFydCA9ZW5zZW1ibCkgIAoKYWxsX3VwX2dlbmVzID0gbWVyZ2UoYWNjX2RlZyxnZW5lZGVzYyxieS54PSJyb3cubmFtZXMiLGJ5LnkgPSAiZXh0ZXJuYWxfZ2VuZV9uYW1lIixhbGwueCA9IFQsc29ydCA9RikKYWxsX3VwX2dlbmVzCmdlbmVzID0gYWxsX3VwX2dlbmVzICU+JSBkcGx5cjo6ZmlsdGVyKFJvdy5uYW1lcyAlaW4lIGMoIk1ZQiIsIkpBRzEiKSkgJT4lIGRwbHlyOjpmaWx0ZXIocF92YWw8MC4wNSkKZ2VuZXMKYGBgCgoKCmBgYHtyfQphbGxfdXBfZ2VuZXMKYGBgCgoKYGBge3J9CiMgbGlicmFyeSgiYmlvbWFSdCIpCiMgbWFydCA8LSB1c2VNYXJ0KGJpb21hcnQ9ImVuc2VtYmwiLCBkYXRhc2V0PSJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiKQojIGFsbF9jb2RpbmdfZ2VuZXMgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoICJoZ25jX3N5bWJvbCIpLCBmaWx0ZXJzID0gYygiYmlvdHlwZSIpLCB2YWx1ZXMgPSBsaXN0KGJpb3R5cGU9InByb3RlaW5fY29kaW5nIiksIG1hcnQgPSBtYXJ0KQoKYWNjMV9jYW5jZXJfY2VsbHMgPSBGaW5kVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyxuZmVhdHVyZXMgPSAxNTAwMCkKYWNjMV9jYW5jZXJfY2VsbHMgPSBTZXRJZGVudChhY2MxX2NhbmNlcl9jZWxscywgdmFsdWUgPSJocHYzM19wb3NpdGl2ZSIpCmZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscykgCmFjY19kZWcgPC0KICBGaW5kTWFya2VycygKICAgIGFjYzFfY2FuY2VyX2NlbGxzLAogICAgaWRlbnQuMSA9ICJwb3NpdGl2ZSIsCiAgICBpZGVudC4yID0gIm5lZ2F0aXZlIiwKICAgIGZlYXR1cmVzID0gZmVhdHVyZXMsCiAgICBkZW5zaWZ5ID0gVCwKICAgIGFzc2F5ID0gIlJOQSIsCiAgICB0ZXN0LnVzZSA9ICJMUiIsCiAgICBsYXRlbnQudmFycyA9ICJwbGF0ZSIsCiAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjI1LAogICAgbWluLnBjdCA9IDAuMTUsCiAgICBtZWFuLmZ4biA9IGZ1bmN0aW9uKHgpIHsKICAgICAgcmV0dXJuKGxvZyhyb3dNZWFucyh4KSArIDEsIGJhc2UgPSAyKSkgIyBjaGFuZ2UgZnVuYyB0byBjYWxjdWxhdGUgbG9nRkMgaW4gbG9nIHNwYWNlIGRhdGEgKGRlZmF1bHQgdG8gZXhwb25lbnQgZGF0YSkKICAgIH0KICApCmFjY19kZWckZmRyPC1wLmFkanVzdChwID0gYXMudmVjdG9yKGFjY19kZWckcF92YWwpICxtZXRob2QgPSAiZmRyIiApCgpgYGAKCgpgYGB7cn0KcmFua2VkX3ZlYyA9IGFjY19kZWdbLCJhdmdfbG9nMkZDIl0lPiUgc2V0TmFtZXMocm93bmFtZXMoYWNjX2RlZykpICU+JSBuYS5vbWl0KCkgIyBtYWtlIG5hbWVkIHZlY3RvcgoKaHlwX29iaiA8LWh5cGVSX2Znc2VhKHNpZ25hdHVyZSA9IHJhbmtlZF92ZWMsZ2VuZXNldHMgPSBnZW5lc2V0cyx1cF9vbmx5ID0gRikKaHlwX2RvdHMoaHlwX29iaixtZXJnZSA9IEYpCgpgYGAKCmBgYHtyfQphY2NfZGVnCmFjY19kZWdbYygiTVlCIiwiSkFHMSIpLF0KCmBgYAoKCmBgYHtyfQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZjX2N1dG9mZiA9IDEuMywgZmRyX2N1dG9mZiA9IDAuMSxzaG93X2dlbmVfbmFtZXMgPSBjKCJNWUIiLCJKQUcxIiksaWRlbnQxID0gIkhQVjMzIHBvc2l0aXZlIixpZGVudDIgPSAiSFBWMzMgbmVnYXRpdmUiLHRvcF9nZW5lc190ZXh0ID0gNSkKYGBgCgoKYGBge3J9CiMgbGlicmFyeSgiYmlvbWFSdCIpCiMgbWFydCA8LSB1c2VNYXJ0KGJpb21hcnQ9ImVuc2VtYmwiLCBkYXRhc2V0PSJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiKQojIGFsbF9jb2RpbmdfZ2VuZXMgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoICJoZ25jX3N5bWJvbCIpLCBmaWx0ZXJzID0gYygiYmlvdHlwZSIpLCB2YWx1ZXMgPSBsaXN0KGJpb3R5cGU9InByb3RlaW5fY29kaW5nIiksIG1hcnQgPSBtYXJ0KQoKYWNjMV9jYW5jZXJfY2VsbHMgPSBGaW5kVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyxuZmVhdHVyZXMgPSAxNTAwMCkKYWNjMV9jYW5jZXJfY2VsbHMgPSBTZXRJZGVudChhY2MxX2NhbmNlcl9jZWxscywgdmFsdWUgPSJocHYzM19wb3NpdGl2ZSIpCmZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscykgCmFjY19kZWcgPC0KICBGaW5kTWFya2VycygKICAgIGFjYzFfY2FuY2VyX2NlbGxzLAogICAgaWRlbnQuMSA9ICJwb3NpdGl2ZSIsCiAgICBpZGVudC4yID0gIm5lZ2F0aXZlIiwKICAgIGZlYXR1cmVzID0gZmVhdHVyZXMsCiAgICBkZW5zaWZ5ID0gVCwKICAgIGFzc2F5ID0gIlJOQSIsCiAgICB0ZXN0LnVzZSA9ICJMUiIsCiAgICBsYXRlbnQudmFycyA9ICJwbGF0ZSIsCiAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjUsCiAgICBtaW4ucGN0ID0gMC4xNSwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4ocm93TWVhbnMoeCkgKyAxKSAjIGNoYW5nZSBmdW5jIHRvIGNhbGN1bGF0ZSBsb2dGQyBpbiBsb2cgc3BhY2UgZGF0YSAoZGVmYXVsdCB0byBleHBvbmVudCBkYXRhKQogICAgfQogICkKYWNjX2RlZyRmZHI8LXAuYWRqdXN0KHAgPSBhcy52ZWN0b3IoYWNjX2RlZyRwX3ZhbCkgLG1ldGhvZCA9ICJmZHIiICkKYGBgCgpgYGB7cn0KYWNjX2RlZwphY2NfZGVnW2MoIk1ZQiIsIkpBRzEiKSxdCgpgYGAKCmBgYHtyfQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZjX2N1dG9mZiA9IDEuMywgZmRyX2N1dG9mZiA9IDAuMSxzaG93X2dlbmVfbmFtZXMgPSBjKCJNWUIiLCJKQUcxIiksaWRlbnQxID0gIkhQVjMzIHBvc2l0aXZlIixpZGVudDIgPSAiSFBWMzMgbmVnYXRpdmUiLHRvcF9nZW5lc190ZXh0ID0gNSkreGxhYigiYXZnIGRpZmYiKQpgYGAKCiMjIyBIUFYgdnMgZ2VuZXMKCmBgYHtyIGZpZy53aWR0aD0xMH0KZ2VuZXMgPSBjKCJBSzQiLCAiQU5MTiIsICJDQVBHIiwgIklGVDEyMiIsICJKQUcxIiwgIk1ZQiIsICJQQlJNMSIgKQpteWJfdnNfaHB2ID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJocHYzM19wb3NpdGl2ZSIsZ2VuZXMpKQpteWJfdnNfaHB2JGhwdjMzX3Bvc2l0aXZlID0gcGFzdGUoIkhQVjMzIixteWJfdnNfaHB2JGhwdjMzX3Bvc2l0aXYpCmRmID0gcmVzaGFwZTI6Om1lbHQobXliX3ZzX2hwdikKCmdnYm94cGxvdCgKICBkZiwKICB4ID0gInZhcmlhYmxlIiwKICB5ID0gInZhbHVlIiwKICBjb2xvciA9ICJocHYzM19wb3NpdGl2ZSIsCiAgcGFsZXR0ZSA9ICJqY28iLAogIGFkZCA9ICJqaXR0ZXIiCikgKyBzdGF0X2NvbXBhcmVfbWVhbnMoCiAgbWV0aG9kID0gIndpbGNveC50ZXN0IiwKICByZWYuZ3JvdXAgPSAiLmFsbC4iLAogIGxhYmVsLnkgPSAxNSwKICBzaXplID0gMwopICsgc3RhdF9zdW1tYXJ5KAogIGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkKICAgIGRhdGEuZnJhbWUoeSA9IG1heCh4KSAqIDEuMiwgbGFiZWwgPSByb3VuZChtZWFuKHgpLCBkaWdpdHMgPSAyKSksCiAgZ2VvbSA9ICJ0ZXh0IiwKICBhZXMoZ3JvdXAgPSBocHYzM19wb3NpdGl2ZSksCiAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguOSkKKQpgYGAKCmBgYHtyfQpub3RjaF9nZW5lcyA9IGMoIkpBRzEiLCJKQUcyIiwiTk9UQ0gzIiwiTk9UQ0gyIiwiTk9UQ0gxIiwiRExMMSIsIk1ZQiIsIkhFUzQiLCJIRVkxIiwiSEVZMiIsIk5SQVJQIiwibXlvX3Njb3JlIikKZm9yIChnZW5lICBpbiBub3RjaF9nZW5lcykgewogIG15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIixnZW5lKSkgCiAgbXliX3ZzX2hwdiRocHYzM19wb3NpdGl2ZSA9IHBhc3RlKCJIUFYzMyIsbXliX3ZzX2hwdiRocHYzM19wb3NpdGl2KQoKICBwID0gZ2dib3hwbG90KG15Yl92c19ocHYsIHggPSAiaHB2MzNfcG9zaXRpdmUiLCB5ID0gZ2VuZSwKICAgICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLAogICAgICAgICAgICBhZGQgPSAiaml0dGVyIikrIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLGNvbXBhcmlzb25zID0gbGlzdChjKCJIUFYzMyBwb3NpdGl2ZSIsIkhQVjMzIG5lZ2F0aXZlIikpKSsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgZGF0YS5mcmFtZSh5PW1heCh4KSoxLjIsIGxhYmVsID0gcGFzdGUoIk1lYW49Iixyb3VuZChtZWFuKHgpLGRpZ2l0cyA9IDIpKSksIGdlb209InRleHQiKSAreWxhYigibG9nMihnZW5lKSIpK2dndGl0bGUoZ2VuZSkKICBwcmludF90YWIocCx0aXRsZSA9IGdlbmUpCn0KCmBgYAoKYGBge3J9Cm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIixjKCJKQUcxIiwiSkFHMiIpKSkgCm15Yl92c19ocHYkaHB2MzNfcG9zaXRpdmUgPSBwYXN0ZSgiSFBWMzMiLG15Yl92c19ocHYkaHB2MzNfcG9zaXRpdikKZGYgPSBtZWx0KG15Yl92c19ocHYpCgpnZ2JveHBsb3QoZGYsIHggPSAidmFyaWFibGUiLCB5ID0gInZhbHVlIixjb2xvciA9ICJocHYzM19wb3NpdGl2ZSIsCiAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgICAgYWRkID0gImppdHRlciIpICsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCByZWYuZ3JvdXAgPSAiLmFsbC4iKSAmIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIGRhdGEuZnJhbWUoeT1tYXgoeCkqMS4yLCBsYWJlbCA9IHBhc3RlKCJNZWFuPSIscm91bmQobWVhbih4KSxkaWdpdHMgPSAyKSkpLCBnZW9tPSJ0ZXh0IikKCgpgYGAKCmBgYHtyfQpub3RjaF90YXJnZXRzID0gYygiTk9UQ0gzIiwiSEVTNCIsIkhFWTEiLCJIRVkyIiwiTlJBUlAiKSAKbm90Y2hfbGlnYW5kID0gYygiSkFHMSIsIkpBRzIiLCJETEwxIikKbm90Y2hfZ2VuZXMgPSBsaXN0KG5vdGNoX3RhcmdldHMgPSBub3RjaF90YXJnZXRzLG5vdGNoX2xpZ2FuZCA9IG5vdGNoX2xpZ2FuZCkKZm9yIChpICBpbiAxOmxlbmd0aChub3RjaF9nZW5lcykpIHsKICBnZW5lcyA9IG5vdGNoX2dlbmVzW1tpXV0KICBuYW1lID0gbmFtZXMoIG5vdGNoX2dlbmVzKVtpXQogIG15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoZ2VuZXMpKSAlPiUgcm93TWVhbnMoKQogIG15Yl92c19ocHYgPSBteWJfdnNfaHB2ICU+JSBjYmluZChGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIikpKQogIGNvbG5hbWVzKG15Yl92c19ocHYpWzFdID0gImdlbmVfc2V0IgogIG15Yl92c19ocHYkaHB2MzNfcG9zaXRpdmUgPSBwYXN0ZSgiSFBWMzMiLG15Yl92c19ocHYkaHB2MzNfcG9zaXRpdikKCiAgcCA9IGdnYm94cGxvdChteWJfdnNfaHB2LCB4ID0gImhwdjMzX3Bvc2l0aXZlIiwgeSA9ICJnZW5lX3NldCIsCiAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgICAgYWRkID0gImppdHRlciIpKyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0Iixjb21wYXJpc29ucyA9IGxpc3QoYygiSFBWMzMgcG9zaXRpdmUiLCJIUFYzMyBuZWdhdGl2ZSIpKSkrIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIGRhdGEuZnJhbWUoeT1tYXgoeCkqMS4yLCBsYWJlbCA9IHBhc3RlKCJNZWFuPSIscm91bmQobWVhbih4KSxkaWdpdHMgPSAyKSkpLCBnZW9tPSJ0ZXh0IikgK3lsYWIoImxvZzIoZ2VuZSkiKStnZ3RpdGxlKG5hbWUpCiBwcmludChwKQp9CgpgYGAKCmBgYHtyfQogIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJNWUIiLCJteW9fc2NvcmUiKSkKZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1NWUIsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCgoKICBjb3JfZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYygiSkFHMSIsIm15b19zY29yZSIpKQpnZ3Bsb3QoY29yX2RhdGEsIGFlcyh4PUpBRzEsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCgogIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJKQUcyIiwibXlvX3Njb3JlIikpCmdncGxvdChjb3JfZGF0YSwgYWVzKHg9SkFHMiwgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKCiAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoIkRMTDEiLCJteW9fc2NvcmUiKSkKZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1ETEwxLCB5PW15b19zY29yZSkpICsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAgKwogIGdlb21fcG9pbnQoKQoKCiAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IG5vdGNoX3RhcmdldHMpICU+JSByb3dNZWFucygpCiAgY29yX2RhdGEgPSBjb3JfZGF0YSAlPiUgY2JpbmQoRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJteW9fc2NvcmUiKSkpCiAgY29sbmFtZXMoY29yX2RhdGEpWzFdID0gIm5vdGNoX3RhcmdldHMiCgogIGdncGxvdChjb3JfZGF0YSwgYWVzKHg9bm90Y2hfdGFyZ2V0cywgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKICAKICAKICAgIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBub3RjaF9saWdhbmQpICU+JSByb3dNZWFucygpCiAgY29yX2RhdGEgPSBjb3JfZGF0YSAlPiUgY2JpbmQoRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJteW9fc2NvcmUiKSkpCiAgY29sbmFtZXMoY29yX2RhdGEpWzFdID0gIm5vdGNoX2xpZ2FuZCIKCiAgZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1ub3RjaF9saWdhbmQsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCiAgCmBgYApgYGB7cn0Kbm90Y2hfc2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHMsdmFycyA9IG5vdGNoX3RhcmdldHMpICU+JSByb3dNZWFucygpCmFsbF9hY2NfY2FuY2VyX2NlbGxzICA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gbm90Y2hfc2NvcmUsY29sLm5hbWUgPSAibm90Y2hfc2NvcmUiKQpGZWF0dXJlUGxvdChvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJub3RjaF9zY29yZSIgKQpgYGAKYGBge3J9Cm15b19tYXJrZXJzID0gYygiVFA2MyIsICJUUDczIiwgIktSVDE0IiwgIkNESDMiKQpzY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gbXlvX21hcmtlcnMpICU+JSByb3dNZWFucygpCmFjYzFfY2FuY2VyX2NlbGxzICA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gc2NvcmUsY29sLm5hbWUgPSAibXlvX21hcmtlcnNfc2NvcmUiKQpGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJteW9fbWFya2Vyc19zY29yZSIscHQuc2l6ZSA9IDIgKQoKCm1hcmtlcnMgPSBjKCJDTEROMyIsICJBTlhBOCIsICJFSEYiLCAiS0lUIikKc2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IG1hcmtlcnMpICU+JSByb3dNZWFucygpCmFjYzFfY2FuY2VyX2NlbGxzICA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gc2NvcmUsY29sLm5hbWUgPSAibHVtX21hcmtlcnNfc2NvcmUiKQpGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJsdW1fbWFya2Vyc19zY29yZSIgLHB0LnNpemUgPSAyICkKYGBgCgoKPHNjcmlwdCBzcmM9Imh0dHBzOi8vaHlwb3RoZXMuaXMvZW1iZWQuanMiIGFzeW5jPjwvc2NyaXB0Pgo=